jekyll-theme-glueckkanja 0.8.3 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -3
  3. data/_sass/font-awesome/scss/_icons.scss +91 -0
  4. data/_sass/font-awesome/scss/_rotated-flipped.scss +3 -2
  5. data/_sass/font-awesome/scss/_variables.scss +93 -1
  6. data/_sass/font-awesome/scss/brands.scss +1 -4
  7. data/_sass/font-awesome/scss/fontawesome.scss +0 -4
  8. data/_sass/font-awesome/scss/regular.scss +1 -4
  9. data/_sass/font-awesome/scss/solid.scss +1 -4
  10. data/_sass/font-awesome/scss/v4-shims.scss +0 -4
  11. data/assets/favicons/de.svg +5 -0
  12. data/assets/favicons/gk-logo-white.png +0 -0
  13. data/assets/favicons/us.svg +10 -0
  14. data/assets/img/cbp-sprite.png +0 -0
  15. data/assets/js/components/_hs.dropdown.js +612 -0
  16. data/assets/js/components/gmap/hs.map.js +347 -0
  17. data/assets/js/components/hs.ajax-autocomplete.js +103 -0
  18. data/assets/js/components/hs.autocomplete-local-search.js +113 -0
  19. data/assets/js/components/hs.autocomplete.js +125 -0
  20. data/assets/js/components/hs.bg-video.js +70 -0
  21. data/assets/js/components/hs.carousel-materialize.js +75 -0
  22. data/assets/js/components/hs.carousel-owl.js +89 -0
  23. data/assets/js/components/hs.carousel-swiper.js +123 -0
  24. data/assets/js/components/hs.carousel.js +283 -0
  25. data/assets/js/components/hs.chart-pie.js +220 -0
  26. data/assets/js/components/hs.chart.js +155 -0
  27. data/assets/js/components/hs.count-qty.js +92 -0
  28. data/assets/js/components/hs.countdown.js +359 -0
  29. data/assets/js/components/hs.counter.js +220 -0
  30. data/assets/js/components/hs.cubeportfolio.js +163 -0
  31. data/assets/js/components/hs.datepicker.js +149 -0
  32. data/assets/js/components/hs.dropdown.js +522 -0
  33. data/assets/js/components/hs.file-attachement.js +135 -0
  34. data/assets/js/components/hs.flickr.js +180 -0
  35. data/assets/js/components/hs.go-to.js +121 -0
  36. data/assets/js/components/hs.header-fullscreen.js +397 -0
  37. data/assets/js/components/hs.header-side.js +1096 -0
  38. data/assets/js/components/hs.header.js +2128 -0
  39. data/assets/js/components/hs.instagram.js +94 -0
  40. data/assets/js/components/hs.map.pin.js +82 -0
  41. data/assets/js/components/hs.map.svg.js +80 -0
  42. data/assets/js/components/hs.markup-copy.js +102 -0
  43. data/assets/js/components/hs.masked-input.js +74 -0
  44. data/assets/js/components/hs.modal-event.js +134 -0
  45. data/assets/js/components/hs.modal-window.js +422 -0
  46. data/assets/js/components/hs.navigation.js +690 -0
  47. data/assets/js/components/hs.nl-form.js +70 -0
  48. data/assets/js/components/hs.onscroll-animation.js +190 -0
  49. data/assets/js/components/hs.popup.js +310 -0
  50. data/assets/js/components/hs.progress-bar.js +353 -0
  51. data/assets/js/components/hs.rating.js +153 -0
  52. data/assets/js/components/hs.scroll-nav.js +373 -0
  53. data/assets/js/components/hs.scrollbar.js +102 -0
  54. data/assets/js/components/hs.select.js +91 -0
  55. data/assets/js/components/hs.slider.js +99 -0
  56. data/assets/js/components/hs.smart-menu.js +233 -0
  57. data/assets/js/components/hs.step-form-old.js +94 -0
  58. data/assets/js/components/hs.step-form.js +93 -0
  59. data/assets/js/components/hs.sticky-block.js +418 -0
  60. data/assets/js/components/hs.tabs.js +186 -0
  61. data/assets/js/components/hs.twitter.js +111 -0
  62. data/assets/js/components/hs.validation.js +111 -0
  63. data/assets/js/components/hs.video-audio.js +70 -0
  64. data/assets/js/components/text-animation/hs.text-slideshow.js +348 -0
  65. data/assets/js/helpers/hs.bg-video.js +23 -0
  66. data/assets/js/helpers/hs.chart.js +66 -0
  67. data/assets/js/helpers/hs.compressed-form.js +55 -0
  68. data/assets/js/helpers/hs.file-attachments.js +39 -0
  69. data/assets/js/helpers/hs.focus-state.js +37 -0
  70. data/assets/js/helpers/hs.hamburgers.js +69 -0
  71. data/assets/js/helpers/hs.height-calc.js +31 -0
  72. data/assets/js/helpers/hs.hover-blocks.js +43 -0
  73. data/assets/js/helpers/hs.modal-markup.js +89 -0
  74. data/assets/js/helpers/hs.navigation-splitted.js +169 -0
  75. data/assets/js/helpers/hs.not-empty-state.js +34 -0
  76. data/assets/js/helpers/hs.rating.js +45 -0
  77. data/assets/js/helpers/hs.selecter.js +14 -0
  78. data/assets/js/helpers/hs.shortcode-filter.js +39 -0
  79. data/assets/js/hs.core.js +250 -0
  80. data/assets/js/hs.popup.js +155 -0
  81. data/assets/js/vendor/jquery.cubeportfolio.js +6054 -0
  82. data/assets/js/vendor/jquery.fancybox.js +4936 -0
  83. data/assets/nav/pixel-trans.png +0 -0
  84. data/assets/nav/pixel-trans@2x.png +0 -0
  85. metadata +75 -1
@@ -0,0 +1,4936 @@
1
+ // ==================================================
2
+ // fancyBox v3.1.24
3
+ //
4
+ // Licensed GPLv3 for open source use
5
+ // or fancyBox Commercial License for commercial use
6
+ //
7
+ // http://fancyapps.com/fancybox/
8
+ // Copyright 2017 fancyApps
9
+ //
10
+ // ==================================================
11
+ ;(function (window, document, $, undefined) {
12
+ 'use strict';
13
+
14
+ // If there's no jQuery, fancyBox can't work
15
+ // =========================================
16
+
17
+ if ( !$ ) {
18
+ return;
19
+ }
20
+
21
+ // Check if fancyBox is already initialized
22
+ // ========================================
23
+
24
+ if ( $.fn.fancybox ) {
25
+
26
+ $.error('fancyBox already initialized');
27
+
28
+ return;
29
+ }
30
+
31
+ // Private default settings
32
+ // ========================
33
+
34
+ var defaults = {
35
+
36
+ // Enable infinite gallery navigation
37
+ loop : false,
38
+
39
+ // Space around image, ignored if zoomed-in or viewport smaller than 800px
40
+ margin : [44, 0],
41
+
42
+ // Horizontal space between slides
43
+ gutter : 50,
44
+
45
+ // Enable keyboard navigation
46
+ keyboard : true,
47
+
48
+ // Should display navigation arrows at the screen edges
49
+ arrows : true,
50
+
51
+ // Should display infobar (counter and arrows at the top)
52
+ infobar : false,
53
+
54
+ // Should display toolbar (buttons at the top)
55
+ toolbar : true,
56
+
57
+ // What buttons should appear in the top right corner.
58
+ // Buttons will be created using templates from `btnTpl` option
59
+ // and they will be placed into toolbar (class="fancybox-toolbar"` element)
60
+ buttons : [
61
+ 'slideShow',
62
+ 'fullScreen',
63
+ 'thumbs',
64
+ 'close'
65
+ ],
66
+
67
+ // Detect "idle" time in seconds
68
+ idleTime : 4,
69
+
70
+ // Should display buttons at top right corner of the content
71
+ // If 'auto' - they will be created for content having type 'html', 'inline' or 'ajax'
72
+ // Use template from `btnTpl.smallBtn` for customization
73
+ smallBtn : 'auto',
74
+
75
+ // Disable right-click and use simple image protection for images
76
+ protect : false,
77
+
78
+ // Shortcut to make content "modal" - disable keyboard navigtion, hide buttons, etc
79
+ modal : false,
80
+
81
+ image : {
82
+
83
+ // Wait for images to load before displaying
84
+ // Requires predefined image dimensions
85
+ // If 'auto' - will zoom in thumbnail if 'width' and 'height' attributes are found
86
+ preload : "auto",
87
+
88
+ },
89
+
90
+ ajax : {
91
+
92
+ // Object containing settings for ajax request
93
+ settings : {
94
+
95
+ // This helps to indicate that request comes from the modal
96
+ // Feel free to change naming
97
+ data : {
98
+ fancybox : true
99
+ }
100
+ }
101
+
102
+ },
103
+
104
+ iframe : {
105
+
106
+ // Iframe template
107
+ tpl : '<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>',
108
+
109
+ // Preload iframe before displaying it
110
+ // This allows to calculate iframe content width and height
111
+ // (note: Due to "Same Origin Policy", you can't get cross domain data).
112
+ preload : true,
113
+
114
+ // Custom CSS styling for iframe wrapping element
115
+ // You can use this to set custom iframe dimensions
116
+ css : {},
117
+
118
+ // Iframe tag attributes
119
+ attr : {
120
+ scrolling : 'auto'
121
+ }
122
+
123
+ },
124
+
125
+ // Open/close animation type
126
+ // Possible values:
127
+ // false - disable
128
+ // "zoom" - zoom images from/to thumbnail
129
+ // "fade"
130
+ // "zoom-in-out"
131
+ //
132
+ animationEffect : "zoom",
133
+
134
+ // Duration in ms for open/close animation
135
+ animationDuration : 366,
136
+
137
+ // Should image change opacity while zooming
138
+ // If opacity is 'auto', then opacity will be changed if image and thumbnail have different aspect ratios
139
+ zoomOpacity : 'auto',
140
+
141
+ // Transition effect between slides
142
+ //
143
+ // Possible values:
144
+ // false - disable
145
+ // "fade'
146
+ // "slide'
147
+ // "circular'
148
+ // "tube'
149
+ // "zoom-in-out'
150
+ // "rotate'
151
+ //
152
+ transitionEffect : "fade",
153
+
154
+ // Duration in ms for transition animation
155
+ transitionDuration : 366,
156
+
157
+ // Custom CSS class for slide element
158
+ slideClass : '',
159
+
160
+ // Custom CSS class for layout
161
+ baseClass : '',
162
+
163
+ // Base template for layout
164
+ baseTpl :
165
+ '<div class="fancybox-container" role="dialog" tabindex="-1">' +
166
+ '<div class="fancybox-bg"></div>' +
167
+ '<div class="fancybox-inner">' +
168
+ '<div class="fancybox-infobar">' +
169
+ '<button data-fancybox-prev title="{{PREV}}" class="fancybox-button fancybox-button--left"></button>' +
170
+ '<div class="fancybox-infobar__body">' +
171
+ '<span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span>' +
172
+ '</div>' +
173
+ '<button data-fancybox-next title="{{NEXT}}" class="fancybox-button fancybox-button--right"></button>' +
174
+ '</div>' +
175
+ '<div class="fancybox-toolbar">' +
176
+ '{{BUTTONS}}' +
177
+ '</div>' +
178
+ '<div class="fancybox-navigation">' +
179
+ '<button data-fancybox-prev title="{{PREV}}" class="fancybox-arrow fancybox-arrow--left" />' +
180
+ '<button data-fancybox-next title="{{NEXT}}" class="fancybox-arrow fancybox-arrow--right" />' +
181
+ '</div>' +
182
+ '<div class="fancybox-stage"></div>' +
183
+ '<div class="fancybox-caption-wrap">' +
184
+ '<div class="fancybox-caption"></div>' +
185
+ '</div>' +
186
+ '</div>' +
187
+ '</div>',
188
+
189
+ // Loading indicator template
190
+ spinnerTpl : '<div class="fancybox-loading"></div>',
191
+
192
+ // Error message template
193
+ errorTpl : '<div class="fancybox-error"><p>{{ERROR}}<p></div>',
194
+
195
+ btnTpl : {
196
+ slideShow : '<button data-fancybox-play class="fancybox-button fancybox-button--play" title="{{PLAY_START}}"></button>',
197
+ fullScreen : '<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fullscreen" title="{{FULL_SCREEN}}"></button>',
198
+ thumbs : '<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="{{THUMBS}}"></button>',
199
+ close : '<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}"></button>',
200
+
201
+ // This small close button will be appended to your html/inline/ajax content by default,
202
+ // if "smallBtn" option is not set to false
203
+ smallBtn : '<button data-fancybox-close class="fancybox-close-small" title="{{CLOSE}}"></button>'
204
+ },
205
+
206
+ // Container is injected into this element
207
+ parentEl : 'body',
208
+
209
+
210
+ // Focus handling
211
+ // ==============
212
+
213
+ // Try to focus on the first focusable element after opening
214
+ autoFocus : true,
215
+
216
+ // Put focus back to active element after closing
217
+ backFocus : true,
218
+
219
+ // Do not let user to focus on element outside modal content
220
+ trapFocus : true,
221
+
222
+
223
+ // Module specific options
224
+ // =======================
225
+
226
+ fullScreen : {
227
+ autoStart : false,
228
+ },
229
+
230
+ touch : {
231
+ vertical : true, // Allow to drag content vertically
232
+ momentum : true // Continue movement after releasing mouse/touch when panning
233
+ },
234
+
235
+ // Hash value when initializing manually,
236
+ // set `false` to disable hash change
237
+ hash : null,
238
+
239
+ // Customize or add new media types
240
+ // Example:
241
+ /*
242
+ media : {
243
+ youtube : {
244
+ params : {
245
+ autoplay : 0
246
+ }
247
+ }
248
+ }
249
+ */
250
+ media : {},
251
+
252
+ slideShow : {
253
+ autoStart : false,
254
+ speed : 4000
255
+ },
256
+
257
+ thumbs : {
258
+ autoStart : false, // Display thumbnails on opening
259
+ hideOnClose : true // Hide thumbnail grid when closing animation starts
260
+ },
261
+
262
+ // Callbacks
263
+ //==========
264
+
265
+ // See Documentation/API/Events for more information
266
+ // Example:
267
+ /*
268
+ afterShow: function( instance, current ) {
269
+ console.info( 'Clicked element:' );
270
+ console.info( current.opts.$orig );
271
+ }
272
+ */
273
+
274
+ onInit : $.noop, // When instance has been initialized
275
+
276
+ beforeLoad : $.noop, // Before the content of a slide is being loaded
277
+ afterLoad : $.noop, // When the content of a slide is done loading
278
+
279
+ beforeShow : $.noop, // Before open animation starts
280
+ afterShow : $.noop, // When content is done loading and animating
281
+
282
+ beforeClose : $.noop, // Before the instance attempts to close. Return false to cancel the close.
283
+ afterClose : $.noop, // After instance has been closed
284
+
285
+ onActivate : $.noop, // When instance is brought to front
286
+ onDeactivate : $.noop, // When other instance has been activated
287
+
288
+
289
+ // Interaction
290
+ // ===========
291
+
292
+ // Use options below to customize taken action when user clicks or double clicks on the fancyBox area,
293
+ // each option can be string or method that returns value.
294
+ //
295
+ // Possible values:
296
+ // "close" - close instance
297
+ // "next" - move to next gallery item
298
+ // "nextOrClose" - move to next gallery item or close if gallery has only one item
299
+ // "toggleControls" - show/hide controls
300
+ // "zoom" - zoom image (if loaded)
301
+ // false - do nothing
302
+
303
+ // Clicked on the content
304
+ clickContent : function( current, event ) {
305
+ return current.type === 'image' ? 'zoom' : false;
306
+ },
307
+
308
+ // Clicked on the slide
309
+ clickSlide : 'close',
310
+
311
+ // Clicked on the background (backdrop) element
312
+ clickOutside : 'close',
313
+
314
+ // Same as previous two, but for double click
315
+ dblclickContent : false,
316
+ dblclickSlide : false,
317
+ dblclickOutside : false,
318
+
319
+
320
+ // Custom options when mobile device is detected
321
+ // =============================================
322
+
323
+ mobile : {
324
+ clickContent : function( current, event ) {
325
+ return current.type === 'image' ? 'toggleControls' : false;
326
+ },
327
+ clickSlide : function( current, event ) {
328
+ return current.type === 'image' ? 'toggleControls' : "close";
329
+ },
330
+ dblclickContent : function( current, event ) {
331
+ return current.type === 'image' ? 'zoom' : false;
332
+ },
333
+ dblclickSlide : function( current, event ) {
334
+ return current.type === 'image' ? 'zoom' : false;
335
+ }
336
+ },
337
+
338
+
339
+ // Internationalization
340
+ // ============
341
+
342
+ lang : 'en',
343
+ i18n : {
344
+ 'en' : {
345
+ CLOSE : 'Close',
346
+ NEXT : 'Next',
347
+ PREV : 'Previous',
348
+ ERROR : 'The requested content cannot be loaded. <br/> Please try again later.',
349
+ PLAY_START : 'Start slideshow',
350
+ PLAY_STOP : 'Pause slideshow',
351
+ FULL_SCREEN : 'Full screen',
352
+ THUMBS : 'Thumbnails'
353
+ },
354
+ 'de' : {
355
+ CLOSE : 'Schliessen',
356
+ NEXT : 'Weiter',
357
+ PREV : 'Zurück',
358
+ ERROR : 'Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es später nochmal.',
359
+ PLAY_START : 'Diaschau starten',
360
+ PLAY_STOP : 'Diaschau beenden',
361
+ FULL_SCREEN : 'Vollbild',
362
+ THUMBS : 'Vorschaubilder'
363
+ }
364
+ }
365
+
366
+ };
367
+
368
+ // Few useful variables and methods
369
+ // ================================
370
+
371
+ var $W = $(window);
372
+ var $D = $(document);
373
+
374
+ var called = 0;
375
+
376
+
377
+ // Check if an object is a jQuery object and not a native JavaScript object
378
+ // ========================================================================
379
+
380
+ var isQuery = function ( obj ) {
381
+ return obj && obj.hasOwnProperty && obj instanceof $;
382
+ };
383
+
384
+
385
+ // Handle multiple browsers for "requestAnimationFrame" and "cancelAnimationFrame"
386
+ // ===============================================================================
387
+
388
+ var requestAFrame = (function () {
389
+ return window.requestAnimationFrame ||
390
+ window.webkitRequestAnimationFrame ||
391
+ window.mozRequestAnimationFrame ||
392
+ window.oRequestAnimationFrame ||
393
+ // if all else fails, use setTimeout
394
+ function (callback) {
395
+ return window.setTimeout(callback, 1000 / 60);
396
+ };
397
+ })();
398
+
399
+
400
+ // Detect the supported transition-end event property name
401
+ // =======================================================
402
+
403
+ var transitionEnd = (function () {
404
+ var t, el = document.createElement("fakeelement");
405
+
406
+ var transitions = {
407
+ "transition" : "transitionend",
408
+ "OTransition" : "oTransitionEnd",
409
+ "MozTransition" : "transitionend",
410
+ "WebkitTransition": "webkitTransitionEnd"
411
+ };
412
+
413
+ for (t in transitions) {
414
+ if (el.style[t] !== undefined){
415
+ return transitions[t];
416
+ }
417
+ }
418
+ })();
419
+
420
+
421
+ // Force redraw on an element.
422
+ // This helps in cases where the browser doesn't redraw an updated element properly.
423
+ // =================================================================================
424
+
425
+ var forceRedraw = function( $el ) {
426
+ return ( $el && $el.length && $el[0].offsetHeight );
427
+ };
428
+
429
+
430
+ // Class definition
431
+ // ================
432
+
433
+ var FancyBox = function( content, opts, index ) {
434
+ var self = this;
435
+
436
+ self.opts = $.extend( true, { index : index }, defaults, opts || {} );
437
+
438
+ // Exclude buttons option from deep merging
439
+ if ( opts && $.isArray( opts.buttons ) ) {
440
+ self.opts.buttons = opts.buttons;
441
+ }
442
+
443
+ self.id = self.opts.id || ++called;
444
+ self.group = [];
445
+
446
+ self.currIndex = parseInt( self.opts.index, 10 ) || 0;
447
+ self.prevIndex = null;
448
+
449
+ self.prevPos = null;
450
+ self.currPos = 0;
451
+
452
+ self.firstRun = null;
453
+
454
+ // Create group elements from original item collection
455
+ self.createGroup( content );
456
+
457
+ if ( !self.group.length ) {
458
+ return;
459
+ }
460
+
461
+ // Save last active element and current scroll position
462
+ self.$lastFocus = $(document.activeElement).blur();
463
+
464
+ // Collection of gallery objects
465
+ self.slides = {};
466
+
467
+ self.init( content );
468
+
469
+ };
470
+
471
+ $.extend(FancyBox.prototype, {
472
+
473
+ // Create DOM structure
474
+ // ====================
475
+
476
+ init : function() {
477
+ var self = this;
478
+
479
+ var testWidth, $container, buttonStr;
480
+
481
+ var firstItemOpts = self.group[ self.currIndex ].opts;
482
+
483
+ self.scrollTop = $D.scrollTop();
484
+ self.scrollLeft = $D.scrollLeft();
485
+
486
+
487
+ // Hide scrollbars
488
+ // ===============
489
+
490
+ if ( !$.fancybox.getInstance() && !$.fancybox.isMobile && $( 'body' ).css('overflow') !== 'hidden' ) {
491
+ testWidth = $( 'body' ).width();
492
+
493
+ $( 'html' ).addClass( 'fancybox-enabled' );
494
+
495
+ // Compare body width after applying "overflow: hidden"
496
+ testWidth = $( 'body' ).width() - testWidth;
497
+
498
+ // If width has changed - compensate missing scrollbars by adding right margin
499
+ if ( testWidth > 1 ) {
500
+ $( 'head' ).append( '<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar, .fancybox-enabled body { margin-right: ' + testWidth + 'px; }</style>' );
501
+ }
502
+ }
503
+
504
+
505
+ // Build html markup and set references
506
+ // ====================================
507
+
508
+ // Build html code for buttons and insert into main template
509
+ buttonStr = '';
510
+
511
+ $.each( firstItemOpts.buttons, function( index, value ) {
512
+ buttonStr += ( firstItemOpts.btnTpl[ value ] || '' );
513
+ });
514
+
515
+ // Create markup from base template, it will be initially hidden to
516
+ // avoid unnecessary work like painting while initializing is not complete
517
+ $container = $( self.translate( self, firstItemOpts.baseTpl.replace( '\{\{BUTTONS\}\}', buttonStr ) ) )
518
+ .addClass( 'fancybox-is-hidden' )
519
+ .attr('id', 'fancybox-container-' + self.id)
520
+ .addClass( firstItemOpts.baseClass )
521
+ .data( 'FancyBox', self )
522
+ .prependTo( firstItemOpts.parentEl );
523
+
524
+ // Create object holding references to jQuery wrapped nodes
525
+ self.$refs = {
526
+ container : $container
527
+ };
528
+
529
+ [ 'bg', 'inner', 'infobar', 'toolbar', 'stage', 'caption' ].forEach(function(item) {
530
+ self.$refs[ item ] = $container.find( '.fancybox-' + item );
531
+ });
532
+
533
+ // Check for redundant elements
534
+ if ( !firstItemOpts.arrows || self.group.length < 2 ) {
535
+ $container.find('.fancybox-navigation').remove();
536
+ }
537
+
538
+ if ( !firstItemOpts.infobar ) {
539
+ self.$refs.infobar.remove();
540
+ }
541
+
542
+ if ( !firstItemOpts.toolbar ) {
543
+ self.$refs.toolbar.remove();
544
+ }
545
+
546
+ self.trigger( 'onInit' );
547
+
548
+ // Bring to front and enable events
549
+ self.activate();
550
+
551
+ // Build slides, load and reveal content
552
+ self.jumpTo( self.currIndex );
553
+ },
554
+
555
+
556
+ // Simple i18n support - replaces object keys found in template
557
+ // with corresponding values
558
+ // ============================================================
559
+
560
+ translate : function( obj, str ) {
561
+ var arr = obj.opts.i18n[ obj.opts.lang ];
562
+
563
+ return str.replace(/\{\{(\w+)\}\}/g, function(match, n) {
564
+ var value = arr[n];
565
+
566
+ if ( value === undefined ) {
567
+ return match;
568
+ }
569
+
570
+ return value;
571
+ });
572
+ },
573
+
574
+ // Create array of gally item objects
575
+ // Check if each object has valid type and content
576
+ // ===============================================
577
+
578
+ createGroup : function ( content ) {
579
+ var self = this;
580
+ var items = $.makeArray( content );
581
+
582
+ $.each(items, function( i, item ) {
583
+ var obj = {},
584
+ opts = {},
585
+ data = [],
586
+ $item,
587
+ type,
588
+ src,
589
+ srcParts;
590
+
591
+ // Step 1 - Make sure we have an object
592
+ // ====================================
593
+
594
+ if ( $.isPlainObject( item ) ) {
595
+
596
+ // We probably have manual usage here, something like
597
+ // $.fancybox.open( [ { src : "image.jpg", type : "image" } ] )
598
+
599
+ obj = item;
600
+ opts = item.opts || item;
601
+
602
+ } else if ( $.type( item ) === 'object' && $( item ).length ) {
603
+
604
+ // Here we propbably have jQuery collection returned by some selector
605
+
606
+ $item = $( item );
607
+ data = $item.data();
608
+
609
+ opts = 'options' in data ? data.options : {};
610
+ opts = $.type( opts ) === 'object' ? opts : {};
611
+
612
+ obj.src = 'src' in data ? data.src : ( opts.src || $item.attr( 'href' ) );
613
+
614
+ [ 'width', 'height', 'thumb', 'type', 'filter' ].forEach(function(item) {
615
+ if ( item in data ) {
616
+ opts[ item ] = data[ item ];
617
+ }
618
+ });
619
+
620
+ if ( 'srcset' in data ) {
621
+ opts.image = { srcset : data.srcset };
622
+ }
623
+
624
+ opts.$orig = $item;
625
+
626
+ if ( !obj.type && !obj.src ) {
627
+ obj.type = 'inline';
628
+ obj.src = item;
629
+ }
630
+
631
+ } else {
632
+
633
+ // Assume we have a simple html code, for example:
634
+ // $.fancybox.open( '<div><h1>Hi!</h1></div>' );
635
+
636
+ obj = {
637
+ type : 'html',
638
+ src : item + ''
639
+ };
640
+
641
+ }
642
+
643
+ // Each gallery object has full collection of options
644
+ obj.opts = $.extend( true, {}, self.opts, opts );
645
+
646
+ if ( $.fancybox.isMobile ) {
647
+ obj.opts = $.extend( true, {}, obj.opts, obj.opts.mobile );
648
+ }
649
+
650
+
651
+ // Step 2 - Make sure we have content type, if not - try to guess
652
+ // ==============================================================
653
+
654
+ type = obj.type || obj.opts.type;
655
+ src = obj.src || '';
656
+
657
+ if ( !type && src ) {
658
+ if ( src.match(/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i) ) {
659
+ type = 'image';
660
+
661
+ } else if ( src.match(/\.(pdf)((\?|#).*)?$/i) ) {
662
+ type = 'pdf';
663
+
664
+ } else if ( src.charAt(0) === '#' ) {
665
+ type = 'inline';
666
+ }
667
+ }
668
+
669
+ obj.type = type;
670
+
671
+
672
+ // Step 3 - Some adjustments
673
+ // =========================
674
+
675
+ obj.index = self.group.length;
676
+
677
+ // Check if $orig and $thumb objects exist
678
+ if ( obj.opts.$orig && !obj.opts.$orig.length ) {
679
+ delete obj.opts.$orig;
680
+ }
681
+
682
+ if ( !obj.opts.$thumb && obj.opts.$orig ) {
683
+ obj.opts.$thumb = obj.opts.$orig.find( 'img:first' );
684
+ }
685
+
686
+ if ( obj.opts.$thumb && !obj.opts.$thumb.length ) {
687
+ delete obj.opts.$thumb;
688
+ }
689
+
690
+ // Caption is a "special" option, it can be passed as a method
691
+ if ( $.type( obj.opts.caption ) === 'function' ) {
692
+ obj.opts.caption = obj.opts.caption.apply( item, [ self, obj ] );
693
+
694
+ } else if ( 'caption' in data ) {
695
+ obj.opts.caption = data.caption;
696
+ }
697
+
698
+ // Make sure we have caption as a string
699
+ obj.opts.caption = obj.opts.caption === undefined ? '' : obj.opts.caption + '';
700
+
701
+ // Check if url contains "filter" used to filter the content
702
+ // Example: "ajax.html #something"
703
+ if ( type === 'ajax' ) {
704
+ srcParts = src.split(/\s+/, 2);
705
+
706
+ if ( srcParts.length > 1 ) {
707
+ obj.src = srcParts.shift();
708
+
709
+ obj.opts.filter = srcParts.shift();
710
+ }
711
+ }
712
+
713
+ if ( obj.opts.smallBtn == 'auto' ) {
714
+
715
+ if ( $.inArray( type, ['html', 'inline', 'ajax'] ) > -1 ) {
716
+ obj.opts.toolbar = false;
717
+ obj.opts.smallBtn = true;
718
+
719
+ } else {
720
+ obj.opts.smallBtn = false;
721
+ }
722
+
723
+ }
724
+
725
+ // If the type is "pdf", then simply load file into iframe
726
+ if ( type === 'pdf' ) {
727
+ obj.type = 'iframe';
728
+
729
+ obj.opts.iframe.preload = false;
730
+ }
731
+
732
+ // Hide all buttons and disable interactivity for modal items
733
+ if ( obj.opts.modal ) {
734
+
735
+ obj.opts = $.extend(true, obj.opts, {
736
+ // Remove buttons
737
+ infobar : 0,
738
+ toolbar : 0,
739
+
740
+ smallBtn : 0,
741
+
742
+ // Disable keyboard navigation
743
+ keyboard : 0,
744
+
745
+ // Disable some modules
746
+ slideShow : 0,
747
+ fullScreen : 0,
748
+ thumbs : 0,
749
+ touch : 0,
750
+
751
+ // Disable click event handlers
752
+ clickContent : false,
753
+ clickSlide : false,
754
+ clickOutside : false,
755
+ dblclickContent : false,
756
+ dblclickSlide : false,
757
+ dblclickOutside : false
758
+ });
759
+
760
+ }
761
+
762
+ // Step 4 - Add processed object to group
763
+ // ======================================
764
+
765
+ self.group.push( obj );
766
+
767
+ });
768
+
769
+ },
770
+
771
+
772
+ // Attach an event handler functions for:
773
+ // - navigation buttons
774
+ // - browser scrolling, resizing;
775
+ // - focusing
776
+ // - keyboard
777
+ // - detect idle
778
+ // ======================================
779
+
780
+ addEvents : function() {
781
+ var self = this;
782
+
783
+ self.removeEvents();
784
+
785
+ // Make navigation elements clickable
786
+ self.$refs.container.on('click.fb-close', '[data-fancybox-close]', function(e) {
787
+ e.stopPropagation();
788
+ e.preventDefault();
789
+
790
+ self.close( e );
791
+
792
+ }).on( 'click.fb-prev touchend.fb-prev', '[data-fancybox-prev]', function(e) {
793
+ e.stopPropagation();
794
+ e.preventDefault();
795
+
796
+ self.previous();
797
+
798
+ }).on( 'click.fb-next touchend.fb-next', '[data-fancybox-next]', function(e) {
799
+ e.stopPropagation();
800
+ e.preventDefault();
801
+
802
+ self.next();
803
+
804
+ });
805
+
806
+
807
+ // Handle page scrolling and browser resizing
808
+ $W.on('orientationchange.fb resize.fb', function(e) {
809
+
810
+ if ( e && e.originalEvent && e.originalEvent.type === "resize" ) {
811
+
812
+ requestAFrame(function() {
813
+ self.update();
814
+ });
815
+
816
+ } else {
817
+
818
+ self.$refs.stage.hide();
819
+
820
+ setTimeout(function() {
821
+ self.$refs.stage.show();
822
+
823
+ self.update();
824
+ }, 500);
825
+
826
+ }
827
+
828
+ });
829
+
830
+ // Trap keyboard focus inside of the modal, so the user does not accidentally tab outside of the modal
831
+ // (a.k.a. "escaping the modal")
832
+ $D.on('focusin.fb', function(e) {
833
+ var instance = $.fancybox ? $.fancybox.getInstance() : null;
834
+
835
+ if ( instance.isClosing || !instance.current || !instance.current.opts.trapFocus || $( e.target ).hasClass( 'fancybox-container' ) || $( e.target ).is( document ) ) {
836
+ return;
837
+ }
838
+
839
+ if ( instance && $( e.target ).css( 'position' ) !== 'fixed' && !instance.$refs.container.has( e.target ).length ) {
840
+ e.stopPropagation();
841
+
842
+ instance.focus();
843
+
844
+ // Sometimes page gets scrolled, set it back
845
+ $W.scrollTop( self.scrollTop ).scrollLeft( self.scrollLeft );
846
+ }
847
+ });
848
+
849
+
850
+ // Enable keyboard navigation
851
+ $D.on('keydown.fb', function (e) {
852
+ var current = self.current,
853
+ keycode = e.keyCode || e.which;
854
+
855
+ if ( !current || !current.opts.keyboard ) {
856
+ return;
857
+ }
858
+
859
+ if ( $(e.target).is('input') || $(e.target).is('textarea') ) {
860
+ return;
861
+ }
862
+
863
+ // Backspace and Esc keys
864
+ if ( keycode === 8 || keycode === 27 ) {
865
+ e.preventDefault();
866
+
867
+ self.close( e );
868
+
869
+ return;
870
+ }
871
+
872
+ // Left arrow and Up arrow
873
+ if ( keycode === 37 || keycode === 38 ) {
874
+ e.preventDefault();
875
+
876
+ self.previous();
877
+
878
+ return;
879
+ }
880
+
881
+ // Righ arrow and Down arrow
882
+ if ( keycode === 39 || keycode === 40 ) {
883
+ e.preventDefault();
884
+
885
+ self.next();
886
+
887
+ return;
888
+ }
889
+
890
+ self.trigger('afterKeydown', e, keycode);
891
+ });
892
+
893
+
894
+ // Hide controls after some inactivity period
895
+ if ( self.group[ self.currIndex ].opts.idleTime ) {
896
+ self.idleSecondsCounter = 0;
897
+
898
+ $D.on('mousemove.fb-idle mouseenter.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle', function() {
899
+ self.idleSecondsCounter = 0;
900
+
901
+ if ( self.isIdle ) {
902
+ self.showControls();
903
+ }
904
+
905
+ self.isIdle = false;
906
+ });
907
+
908
+ self.idleInterval = window.setInterval(function() {
909
+
910
+ self.idleSecondsCounter++;
911
+
912
+ if ( self.idleSecondsCounter >= self.group[ self.currIndex ].opts.idleTime ) {
913
+ self.isIdle = true;
914
+ self.idleSecondsCounter = 0;
915
+
916
+ self.hideControls();
917
+ }
918
+
919
+ }, 1000);
920
+ }
921
+
922
+ },
923
+
924
+
925
+ // Remove events added by the core
926
+ // ===============================
927
+
928
+ removeEvents : function () {
929
+ var self = this;
930
+
931
+ $W.off( 'orientationchange.fb resize.fb' );
932
+ $D.off( 'focusin.fb keydown.fb .fb-idle' );
933
+
934
+ this.$refs.container.off( '.fb-close .fb-prev .fb-next' );
935
+
936
+ if ( self.idleInterval ) {
937
+ window.clearInterval( self.idleInterval );
938
+
939
+ self.idleInterval = null;
940
+ }
941
+ },
942
+
943
+
944
+ // Change to previous gallery item
945
+ // ===============================
946
+
947
+ previous : function( duration ) {
948
+ return this.jumpTo( this.currPos - 1, duration );
949
+ },
950
+
951
+
952
+ // Change to next gallery item
953
+ // ===========================
954
+
955
+ next : function( duration ) {
956
+ return this.jumpTo( this.currPos + 1, duration );
957
+ },
958
+
959
+
960
+ // Switch to selected gallery item
961
+ // ===============================
962
+
963
+ jumpTo : function ( pos, duration, slide ) {
964
+ var self = this,
965
+ firstRun,
966
+ loop,
967
+ current,
968
+ previous,
969
+ canvasWidth,
970
+ currentPos,
971
+ transitionProps;
972
+
973
+ var groupLen = self.group.length;
974
+
975
+ if ( self.isSliding || self.isClosing || ( self.isAnimating && self.firstRun ) ) {
976
+ return;
977
+ }
978
+
979
+ pos = parseInt( pos, 10 );
980
+ loop = self.current ? self.current.opts.loop : self.opts.loop;
981
+
982
+ if ( !loop && ( pos < 0 || pos >= groupLen ) ) {
983
+ return false;
984
+ }
985
+
986
+ firstRun = self.firstRun = ( self.firstRun === null );
987
+
988
+ if ( groupLen < 2 && !firstRun && !!self.isSliding ) {
989
+ return;
990
+ }
991
+
992
+ previous = self.current;
993
+
994
+ self.prevIndex = self.currIndex;
995
+ self.prevPos = self.currPos;
996
+
997
+ // Create slides
998
+ current = self.createSlide( pos );
999
+
1000
+ if ( groupLen > 1 ) {
1001
+ if ( loop || current.index > 0 ) {
1002
+ self.createSlide( pos - 1 );
1003
+ }
1004
+
1005
+ if ( loop || current.index < groupLen - 1 ) {
1006
+ self.createSlide( pos + 1 );
1007
+ }
1008
+ }
1009
+
1010
+ self.current = current;
1011
+ self.currIndex = current.index;
1012
+ self.currPos = current.pos;
1013
+
1014
+ self.trigger( 'beforeShow', firstRun );
1015
+
1016
+ self.updateControls();
1017
+
1018
+ currentPos = $.fancybox.getTranslate( current.$slide );
1019
+
1020
+ current.isMoved = ( currentPos.left !== 0 || currentPos.top !== 0 ) && !current.$slide.hasClass( 'fancybox-animated' );
1021
+ current.forcedDuration = undefined;
1022
+
1023
+ if ( $.isNumeric( duration ) ) {
1024
+ current.forcedDuration = duration;
1025
+ } else {
1026
+ duration = current.opts[ firstRun ? 'animationDuration' : 'transitionDuration' ];
1027
+ }
1028
+
1029
+ duration = parseInt( duration, 10 );
1030
+
1031
+ // Fresh start - reveal container, current slide and start loading content
1032
+ if ( firstRun ) {
1033
+
1034
+ if ( current.opts.animationEffect && duration ) {
1035
+ self.$refs.container.css( 'transition-duration', duration + 'ms' );
1036
+ }
1037
+
1038
+ self.$refs.container.removeClass( 'fancybox-is-hidden' );
1039
+
1040
+ forceRedraw( self.$refs.container );
1041
+
1042
+ self.$refs.container.addClass( 'fancybox-is-open' );
1043
+
1044
+ // Make first slide visible (to display loading icon, if needed)
1045
+ current.$slide.addClass( 'fancybox-slide--current' );
1046
+
1047
+ self.loadSlide( current );
1048
+
1049
+ self.preload();
1050
+
1051
+ return;
1052
+ }
1053
+
1054
+ // Clean up
1055
+ $.each(self.slides, function( index, slide ) {
1056
+ $.fancybox.stop( slide.$slide );
1057
+ });
1058
+
1059
+ // Make current that slide is visible even if content is still loading
1060
+ current.$slide.removeClass( 'fancybox-slide--next fancybox-slide--previous' ).addClass( 'fancybox-slide--current' );
1061
+
1062
+ // If slides have been dragged, animate them to correct position
1063
+ if ( current.isMoved ) {
1064
+ canvasWidth = Math.round( current.$slide.width() );
1065
+
1066
+ $.each(self.slides, function( index, slide ) {
1067
+ var pos = slide.pos - current.pos;
1068
+
1069
+ $.fancybox.animate( slide.$slide, {
1070
+ top : 0,
1071
+ left : ( pos * canvasWidth ) + ( pos * slide.opts.gutter )
1072
+ }, duration, function() {
1073
+
1074
+ slide.$slide.removeAttr('style').removeClass( 'fancybox-slide--next fancybox-slide--previous' );
1075
+
1076
+ if ( slide.pos === self.currPos ) {
1077
+ current.isMoved = false;
1078
+
1079
+ self.complete();
1080
+ }
1081
+ });
1082
+ });
1083
+
1084
+ } else {
1085
+ self.$refs.stage.children().removeAttr( 'style' );
1086
+ }
1087
+
1088
+ // Start transition that reveals current content
1089
+ // or wait when it will be loaded
1090
+
1091
+ if ( current.isLoaded ) {
1092
+ self.revealContent( current );
1093
+
1094
+ } else {
1095
+ self.loadSlide( current );
1096
+ }
1097
+
1098
+ self.preload();
1099
+
1100
+ if ( previous.pos === current.pos ) {
1101
+ return;
1102
+ }
1103
+
1104
+ // Handle previous slide
1105
+ // =====================
1106
+
1107
+ transitionProps = 'fancybox-slide--' + ( previous.pos > current.pos ? 'next' : 'previous' );
1108
+
1109
+ previous.$slide.removeClass( 'fancybox-slide--complete fancybox-slide--current fancybox-slide--next fancybox-slide--previous' );
1110
+
1111
+ previous.isComplete = false;
1112
+
1113
+ if ( !duration || ( !current.isMoved && !current.opts.transitionEffect ) ) {
1114
+ return;
1115
+ }
1116
+
1117
+ if ( current.isMoved ) {
1118
+ previous.$slide.addClass( transitionProps );
1119
+
1120
+ } else {
1121
+
1122
+ transitionProps = 'fancybox-animated ' + transitionProps + ' fancybox-fx-' + current.opts.transitionEffect;
1123
+
1124
+ $.fancybox.animate( previous.$slide, transitionProps, duration, function() {
1125
+ previous.$slide.removeClass( transitionProps ).removeAttr( 'style' );
1126
+ });
1127
+
1128
+ }
1129
+
1130
+ },
1131
+
1132
+
1133
+ // Create new "slide" element
1134
+ // These are gallery items that are actually added to DOM
1135
+ // =======================================================
1136
+
1137
+ createSlide : function( pos ) {
1138
+
1139
+ var self = this;
1140
+ var $slide;
1141
+ var index;
1142
+
1143
+ index = pos % self.group.length;
1144
+ index = index < 0 ? self.group.length + index : index;
1145
+
1146
+ if ( !self.slides[ pos ] && self.group[ index ] ) {
1147
+ $slide = $('<div class="fancybox-slide"></div>').appendTo( self.$refs.stage );
1148
+
1149
+ self.slides[ pos ] = $.extend( true, {}, self.group[ index ], {
1150
+ pos : pos,
1151
+ $slide : $slide,
1152
+ isLoaded : false,
1153
+ });
1154
+
1155
+ self.updateSlide( self.slides[ pos ] );
1156
+ }
1157
+
1158
+ return self.slides[ pos ];
1159
+ },
1160
+
1161
+
1162
+ // Scale image to the actual size of the image
1163
+ // ===========================================
1164
+
1165
+ scaleToActual : function( x, y, duration ) {
1166
+
1167
+ var self = this;
1168
+
1169
+ var current = self.current;
1170
+ var $what = current.$content;
1171
+
1172
+ var imgPos, posX, posY, scaleX, scaleY;
1173
+
1174
+ var canvasWidth = parseInt( current.$slide.width(), 10 );
1175
+ var canvasHeight = parseInt( current.$slide.height(), 10 );
1176
+
1177
+ var newImgWidth = current.width;
1178
+ var newImgHeight = current.height;
1179
+
1180
+ if ( !( current.type == 'image' && !current.hasError) || !$what || self.isAnimating) {
1181
+ return;
1182
+ }
1183
+
1184
+ $.fancybox.stop( $what );
1185
+
1186
+ self.isAnimating = true;
1187
+
1188
+ x = x === undefined ? canvasWidth * 0.5 : x;
1189
+ y = y === undefined ? canvasHeight * 0.5 : y;
1190
+
1191
+ imgPos = $.fancybox.getTranslate( $what );
1192
+
1193
+ scaleX = newImgWidth / imgPos.width;
1194
+ scaleY = newImgHeight / imgPos.height;
1195
+
1196
+ // Get center position for original image
1197
+ posX = ( canvasWidth * 0.5 - newImgWidth * 0.5 );
1198
+ posY = ( canvasHeight * 0.5 - newImgHeight * 0.5 );
1199
+
1200
+ // Make sure image does not move away from edges
1201
+ if ( newImgWidth > canvasWidth ) {
1202
+ posX = imgPos.left * scaleX - ( ( x * scaleX ) - x );
1203
+
1204
+ if ( posX > 0 ) {
1205
+ posX = 0;
1206
+ }
1207
+
1208
+ if ( posX < canvasWidth - newImgWidth ) {
1209
+ posX = canvasWidth - newImgWidth;
1210
+ }
1211
+ }
1212
+
1213
+ if ( newImgHeight > canvasHeight) {
1214
+ posY = imgPos.top * scaleY - ( ( y * scaleY ) - y );
1215
+
1216
+ if ( posY > 0 ) {
1217
+ posY = 0;
1218
+ }
1219
+
1220
+ if ( posY < canvasHeight - newImgHeight ) {
1221
+ posY = canvasHeight - newImgHeight;
1222
+ }
1223
+ }
1224
+
1225
+ self.updateCursor( newImgWidth, newImgHeight );
1226
+
1227
+ $.fancybox.animate( $what, {
1228
+ top : posY,
1229
+ left : posX,
1230
+ scaleX : scaleX,
1231
+ scaleY : scaleY
1232
+ }, duration || 330, function() {
1233
+ self.isAnimating = false;
1234
+ });
1235
+
1236
+ // Stop slideshow
1237
+ if ( self.SlideShow && self.SlideShow.isActive ) {
1238
+ self.SlideShow.stop();
1239
+ }
1240
+ },
1241
+
1242
+
1243
+ // Scale image to fit inside parent element
1244
+ // ========================================
1245
+
1246
+ scaleToFit : function( duration ) {
1247
+
1248
+ var self = this;
1249
+
1250
+ var current = self.current;
1251
+ var $what = current.$content;
1252
+ var end;
1253
+
1254
+ if ( !( current.type == 'image' && !current.hasError) || !$what || self.isAnimating ) {
1255
+ return;
1256
+ }
1257
+
1258
+ $.fancybox.stop( $what );
1259
+
1260
+ self.isAnimating = true;
1261
+
1262
+ end = self.getFitPos( current );
1263
+
1264
+ self.updateCursor( end.width, end.height );
1265
+
1266
+ $.fancybox.animate( $what, {
1267
+ top : end.top,
1268
+ left : end.left,
1269
+ scaleX : end.width / $what.width(),
1270
+ scaleY : end.height / $what.height()
1271
+ }, duration || 330, function() {
1272
+ self.isAnimating = false;
1273
+ });
1274
+
1275
+ },
1276
+
1277
+ // Calculate image size to fit inside viewport
1278
+ // ===========================================
1279
+
1280
+ getFitPos : function( slide ) {
1281
+ var self = this;
1282
+ var $what = slide.$content;
1283
+
1284
+ var imgWidth = slide.width;
1285
+ var imgHeight = slide.height;
1286
+
1287
+ var margin = slide.opts.margin;
1288
+
1289
+ var canvasWidth, canvasHeight, minRatio, width, height;
1290
+
1291
+ if ( !$what || !$what.length || ( !imgWidth && !imgHeight) ) {
1292
+ return false;
1293
+ }
1294
+
1295
+ // Convert "margin to CSS style: [ top, right, bottom, left ]
1296
+ if ( $.type( margin ) === "number" ) {
1297
+ margin = [ margin, margin ];
1298
+ }
1299
+
1300
+ if ( margin.length == 2 ) {
1301
+ margin = [ margin[0], margin[1], margin[0], margin[1] ];
1302
+ }
1303
+
1304
+ if ( $W.width() < 800 ) {
1305
+ margin = [ 0, 0, 0, 0 ];
1306
+ }
1307
+
1308
+ // We can not use $slide width here, because it can have different diemensions while in transiton
1309
+ canvasWidth = parseInt( self.$refs.stage.width(), 10 ) - ( margin[ 1 ] + margin[ 3 ] );
1310
+ canvasHeight = parseInt( self.$refs.stage.height(), 10 ) - ( margin[ 0 ] + margin[ 2 ] );
1311
+
1312
+ minRatio = Math.min(1, canvasWidth / imgWidth, canvasHeight / imgHeight );
1313
+
1314
+ width = Math.floor( minRatio * imgWidth );
1315
+ height = Math.floor( minRatio * imgHeight );
1316
+
1317
+ // Use floor rounding to make sure it really fits
1318
+ return {
1319
+ top : Math.floor( ( canvasHeight - height ) * 0.5 ) + margin[ 0 ],
1320
+ left : Math.floor( ( canvasWidth - width ) * 0.5 ) + margin[ 3 ],
1321
+ width : width,
1322
+ height : height
1323
+ };
1324
+
1325
+ },
1326
+
1327
+
1328
+ // Update position and content of all slides
1329
+ // =========================================
1330
+
1331
+ update : function() {
1332
+
1333
+ var self = this;
1334
+
1335
+ $.each( self.slides, function( key, slide ) {
1336
+ self.updateSlide( slide );
1337
+ });
1338
+
1339
+ },
1340
+
1341
+
1342
+ // Update slide position and scale content to fit
1343
+ // ==============================================
1344
+
1345
+ updateSlide : function( slide ) {
1346
+
1347
+ var self = this;
1348
+ var $what = slide.$content;
1349
+
1350
+ if ( $what && ( slide.width || slide.height ) ) {
1351
+ $.fancybox.stop( $what );
1352
+
1353
+ $.fancybox.setTranslate( $what, self.getFitPos( slide ) );
1354
+
1355
+ if ( slide.pos === self.currPos ) {
1356
+ self.updateCursor();
1357
+ }
1358
+ }
1359
+
1360
+ slide.$slide.trigger( 'refresh' );
1361
+
1362
+ self.trigger( 'onUpdate', slide );
1363
+
1364
+ },
1365
+
1366
+ // Update cursor style depending if content can be zoomed
1367
+ // ======================================================
1368
+
1369
+ updateCursor : function( nextWidth, nextHeight ) {
1370
+
1371
+ var self = this;
1372
+ var isScaledDown;
1373
+
1374
+ var $container = self.$refs.container.removeClass('fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-drag fancybox-can-zoomOut');
1375
+
1376
+ if ( !self.current || self.isClosing ) {
1377
+ return;
1378
+ }
1379
+
1380
+ if ( self.isZoomable() ) {
1381
+
1382
+ $container.addClass( 'fancybox-is-zoomable' );
1383
+
1384
+ if ( nextWidth !== undefined && nextHeight !== undefined ) {
1385
+ isScaledDown = nextWidth < self.current.width && nextHeight < self.current.height;
1386
+
1387
+ } else {
1388
+ isScaledDown = self.isScaledDown();
1389
+ }
1390
+
1391
+ if ( isScaledDown ) {
1392
+
1393
+ // If image is scaled down, then, obviously, it can be zoomed to full size
1394
+ $container.addClass('fancybox-can-zoomIn');
1395
+
1396
+ } else {
1397
+
1398
+ if ( self.current.opts.touch ) {
1399
+
1400
+ // If image size ir largen than available available and touch module is not disable,
1401
+ // then user can do panning
1402
+ $container.addClass('fancybox-can-drag');
1403
+
1404
+ } else {
1405
+ $container.addClass('fancybox-can-zoomOut');
1406
+ }
1407
+
1408
+ }
1409
+
1410
+ } else if ( self.current.opts.touch ) {
1411
+ $container.addClass('fancybox-can-drag');
1412
+ }
1413
+
1414
+ },
1415
+
1416
+
1417
+ // Check if current slide is zoomable
1418
+ // ==================================
1419
+
1420
+ isZoomable : function() {
1421
+
1422
+ var self = this;
1423
+
1424
+ var current = self.current;
1425
+ var fitPos;
1426
+
1427
+ if ( !current || self.isClosing ) {
1428
+ return;
1429
+ }
1430
+
1431
+ // Assume that slide is zoomable if
1432
+ // - image is loaded successfuly
1433
+ // - click action is "zoom"
1434
+ // - actual size of the image is smaller than available area
1435
+ if ( current.type === 'image' && current.isLoaded && !current.hasError &&
1436
+ ( current.opts.clickContent === 'zoom' || ( $.isFunction( current.opts.clickContent ) && current.opts.clickContent( current ) === "zoom" ) )
1437
+ ) {
1438
+
1439
+ fitPos = self.getFitPos( current );
1440
+
1441
+ if ( current.width > fitPos.width || current.height > fitPos.height ) {
1442
+ return true;
1443
+ }
1444
+
1445
+ }
1446
+
1447
+ return false;
1448
+
1449
+ },
1450
+
1451
+
1452
+ // Check if current image dimensions are smaller than actual
1453
+ // =========================================================
1454
+
1455
+ isScaledDown : function() {
1456
+
1457
+ var self = this;
1458
+
1459
+ var current = self.current;
1460
+ var $what = current.$content;
1461
+
1462
+ var rez = false;
1463
+
1464
+ if ( $what ) {
1465
+ rez = $.fancybox.getTranslate( $what );
1466
+ rez = rez.width < current.width || rez.height < current.height;
1467
+ }
1468
+
1469
+ return rez;
1470
+
1471
+ },
1472
+
1473
+
1474
+ // Check if image dimensions exceed parent element
1475
+ // ===============================================
1476
+
1477
+ canPan : function() {
1478
+
1479
+ var self = this;
1480
+
1481
+ var current = self.current;
1482
+ var $what = current.$content;
1483
+
1484
+ var rez = false;
1485
+
1486
+ if ( $what ) {
1487
+ rez = self.getFitPos( current );
1488
+ rez = Math.abs( $what.width() - rez.width ) > 1 || Math.abs( $what.height() - rez.height ) > 1;
1489
+
1490
+ }
1491
+
1492
+ return rez;
1493
+
1494
+ },
1495
+
1496
+
1497
+ // Load content into the slide
1498
+ // ===========================
1499
+
1500
+ loadSlide : function( slide ) {
1501
+
1502
+ var self = this, type, $slide;
1503
+ var ajaxLoad;
1504
+
1505
+ if ( slide.isLoading ) {
1506
+ return;
1507
+ }
1508
+
1509
+ if ( slide.isLoaded ) {
1510
+ return;
1511
+ }
1512
+
1513
+ slide.isLoading = true;
1514
+
1515
+ self.trigger( 'beforeLoad', slide );
1516
+
1517
+ type = slide.type;
1518
+ $slide = slide.$slide;
1519
+
1520
+ $slide
1521
+ .off( 'refresh' )
1522
+ .trigger( 'onReset' )
1523
+ .addClass( 'fancybox-slide--' + ( type || 'unknown' ) )
1524
+ .addClass( slide.opts.slideClass );
1525
+
1526
+ // Create content depending on the type
1527
+
1528
+ switch ( type ) {
1529
+
1530
+ case 'image':
1531
+
1532
+ self.setImage( slide );
1533
+
1534
+ break;
1535
+
1536
+ case 'iframe':
1537
+
1538
+ self.setIframe( slide );
1539
+
1540
+ break;
1541
+
1542
+ case 'html':
1543
+
1544
+ self.setContent( slide, slide.src || slide.content );
1545
+
1546
+ break;
1547
+
1548
+ case 'inline':
1549
+
1550
+ if ( $( slide.src ).length ) {
1551
+ self.setContent( slide, $( slide.src ) );
1552
+
1553
+ } else {
1554
+ self.setError( slide );
1555
+ }
1556
+
1557
+ break;
1558
+
1559
+ case 'ajax':
1560
+
1561
+ self.showLoading( slide );
1562
+
1563
+ ajaxLoad = $.ajax( $.extend( {}, slide.opts.ajax.settings, {
1564
+ url : slide.src,
1565
+ success : function ( data, textStatus ) {
1566
+
1567
+ if ( textStatus === 'success' ) {
1568
+ self.setContent( slide, data );
1569
+ }
1570
+
1571
+ },
1572
+ error : function ( jqXHR, textStatus ) {
1573
+
1574
+ if ( jqXHR && textStatus !== 'abort' ) {
1575
+ self.setError( slide );
1576
+ }
1577
+
1578
+ }
1579
+ }));
1580
+
1581
+ $slide.one( 'onReset', function () {
1582
+ ajaxLoad.abort();
1583
+ });
1584
+
1585
+ break;
1586
+
1587
+ default:
1588
+
1589
+ self.setError( slide );
1590
+
1591
+ break;
1592
+
1593
+ }
1594
+
1595
+ return true;
1596
+
1597
+ },
1598
+
1599
+
1600
+ // Use thumbnail image, if possible
1601
+ // ================================
1602
+
1603
+ setImage : function( slide ) {
1604
+
1605
+ var self = this;
1606
+ var srcset = slide.opts.image.srcset;
1607
+
1608
+ var found, temp, pxRatio, windowWidth;
1609
+
1610
+ // If we have "srcset", then we need to find matching "src" value.
1611
+ // This is necessary, because when you set an src attribute, the browser will preload the image
1612
+ // before any javascript or even CSS is applied.
1613
+ if ( srcset ) {
1614
+ pxRatio = window.devicePixelRatio || 1;
1615
+ windowWidth = window.innerWidth * pxRatio;
1616
+
1617
+ temp = srcset.split(',').map(function ( el ) {
1618
+ var ret = {};
1619
+
1620
+ el.trim().split(/\s+/).forEach(function ( el, i ) {
1621
+ var value = parseInt( el.substring(0, el.length - 1), 10 );
1622
+
1623
+ if ( i === 0 ) {
1624
+ return ( ret.url = el );
1625
+ }
1626
+
1627
+ if ( value ) {
1628
+ ret.value = value;
1629
+ ret.postfix = el[ el.length - 1 ];
1630
+ }
1631
+
1632
+ });
1633
+
1634
+ return ret;
1635
+ });
1636
+
1637
+ // Sort by value
1638
+ temp.sort(function (a, b) {
1639
+ return a.value - b.value;
1640
+ });
1641
+
1642
+ // Ok, now we have an array of all srcset values
1643
+ for ( var j = 0; j < temp.length; j++ ) {
1644
+ var el = temp[ j ];
1645
+
1646
+ if ( ( el.postfix === 'w' && el.value >= windowWidth ) || ( el.postfix === 'x' && el.value >= pxRatio ) ) {
1647
+ found = el;
1648
+ break;
1649
+ }
1650
+ }
1651
+
1652
+ // If not found, take the last one
1653
+ if ( !found && temp.length ) {
1654
+ found = temp[ temp.length - 1 ];
1655
+ }
1656
+
1657
+ if ( found ) {
1658
+ slide.src = found.url;
1659
+
1660
+ // If we have default width/height values, we can calculate height for matching source
1661
+ if ( slide.width && slide.height && found.postfix == 'w' ) {
1662
+ slide.height = ( slide.width / slide.height ) * found.value;
1663
+ slide.width = found.value;
1664
+ }
1665
+ }
1666
+ }
1667
+
1668
+ // This will be wrapper containing both ghost and actual image
1669
+ slide.$content = $('<div class="fancybox-image-wrap"></div>')
1670
+ .addClass( 'fancybox-is-hidden' )
1671
+ .appendTo( slide.$slide );
1672
+
1673
+
1674
+ // If we have a thumbnail, we can display it while actual image is loading
1675
+ // Users will not stare at black screen and actual image will appear gradually
1676
+ if ( slide.opts.preload !== false && slide.opts.width && slide.opts.height && ( slide.opts.thumb || slide.opts.$thumb ) ) {
1677
+
1678
+ slide.width = slide.opts.width;
1679
+ slide.height = slide.opts.height;
1680
+
1681
+ slide.$ghost = $('<img />')
1682
+ .one('error', function() {
1683
+
1684
+ $(this).remove();
1685
+
1686
+ slide.$ghost = null;
1687
+
1688
+ self.setBigImage( slide );
1689
+
1690
+ })
1691
+ .one('load', function() {
1692
+
1693
+ self.afterLoad( slide );
1694
+
1695
+ self.setBigImage( slide );
1696
+
1697
+ })
1698
+ .addClass( 'fancybox-image' )
1699
+ .appendTo( slide.$content )
1700
+ .attr( 'src', slide.opts.thumb || slide.opts.$thumb.attr( 'src' ) );
1701
+
1702
+ } else {
1703
+
1704
+ self.setBigImage( slide );
1705
+
1706
+ }
1707
+
1708
+ },
1709
+
1710
+
1711
+ // Create full-size image
1712
+ // ======================
1713
+
1714
+ setBigImage : function ( slide ) {
1715
+ var self = this;
1716
+ var $img = $('<img />');
1717
+
1718
+ slide.$image = $img
1719
+ .one('error', function() {
1720
+
1721
+ self.setError( slide );
1722
+
1723
+ })
1724
+ .one('load', function() {
1725
+
1726
+ // Clear timeout that checks if loading icon needs to be displayed
1727
+ clearTimeout( slide.timouts );
1728
+
1729
+ slide.timouts = null;
1730
+
1731
+ if ( self.isClosing ) {
1732
+ return;
1733
+ }
1734
+
1735
+ slide.width = this.naturalWidth;
1736
+ slide.height = this.naturalHeight;
1737
+
1738
+ if ( slide.opts.image.srcset ) {
1739
+ $img.attr( 'sizes', '100vw' ).attr( 'srcset', slide.opts.image.srcset );
1740
+ }
1741
+
1742
+ self.hideLoading( slide );
1743
+
1744
+ if ( slide.$ghost ) {
1745
+
1746
+ slide.timouts = setTimeout(function() {
1747
+ slide.timouts = null;
1748
+
1749
+ slide.$ghost.hide();
1750
+
1751
+ }, Math.min( 300, Math.max( 1000, slide.height / 1600 ) ) );
1752
+
1753
+ } else {
1754
+ self.afterLoad( slide );
1755
+ }
1756
+
1757
+ })
1758
+ .addClass( 'fancybox-image' )
1759
+ .attr('src', slide.src)
1760
+ .appendTo( slide.$content );
1761
+
1762
+ if ( $img[0].complete ) {
1763
+ $img.trigger( 'load' );
1764
+
1765
+ } else if( $img[0].error ) {
1766
+ $img.trigger( 'error' );
1767
+
1768
+ } else {
1769
+
1770
+ slide.timouts = setTimeout(function() {
1771
+ if ( !$img[0].complete && !slide.hasError ) {
1772
+ self.showLoading( slide );
1773
+ }
1774
+
1775
+ }, 100);
1776
+
1777
+ }
1778
+
1779
+ },
1780
+
1781
+
1782
+ // Create iframe wrapper, iframe and bindings
1783
+ // ==========================================
1784
+
1785
+ setIframe : function( slide ) {
1786
+ var self = this,
1787
+ opts = slide.opts.iframe,
1788
+ $slide = slide.$slide,
1789
+ $iframe;
1790
+
1791
+ slide.$content = $('<div class="fancybox-content' + ( opts.preload ? ' fancybox-is-hidden' : '' ) + '"></div>')
1792
+ .css( opts.css )
1793
+ .appendTo( $slide );
1794
+
1795
+ $iframe = $( opts.tpl.replace(/\{rnd\}/g, new Date().getTime()) )
1796
+ .attr( opts.attr )
1797
+ .appendTo( slide.$content );
1798
+
1799
+ if ( opts.preload ) {
1800
+
1801
+ self.showLoading( slide );
1802
+
1803
+ // Unfortunately, it is not always possible to determine if iframe is successfully loaded
1804
+ // (due to browser security policy)
1805
+
1806
+ $iframe.on('load.fb error.fb', function(e) {
1807
+ this.isReady = 1;
1808
+
1809
+ slide.$slide.trigger( 'refresh' );
1810
+
1811
+ self.afterLoad( slide );
1812
+ });
1813
+
1814
+ // Recalculate iframe content size
1815
+ // ===============================
1816
+
1817
+ $slide.on('refresh.fb', function() {
1818
+ var $wrap = slide.$content,
1819
+ $contents,
1820
+ $body,
1821
+ scrollWidth,
1822
+ frameWidth,
1823
+ frameHeight;
1824
+
1825
+ if ( $iframe[0].isReady !== 1 ) {
1826
+ return;
1827
+ }
1828
+
1829
+ // Check if content is accessible,
1830
+ // it will fail if frame is not with the same origin
1831
+
1832
+ try {
1833
+ $contents = $iframe.contents();
1834
+ $body = $contents.find('body');
1835
+
1836
+ } catch (ignore) {}
1837
+
1838
+ // Calculate dimensions for the wrapper
1839
+ if ( $body && $body.length && !( opts.css.width !== undefined && opts.css.height !== undefined ) ) {
1840
+
1841
+ scrollWidth = $iframe[0].contentWindow.document.documentElement.scrollWidth;
1842
+
1843
+ frameWidth = Math.ceil( $body.outerWidth(true) + ( $wrap.width() - scrollWidth ) );
1844
+ frameHeight = Math.ceil( $body.outerHeight(true) );
1845
+
1846
+ // Resize wrapper to fit iframe content
1847
+ $wrap.css({
1848
+ 'width' : opts.css.width === undefined ? frameWidth + ( $wrap.outerWidth() - $wrap.innerWidth() ) : opts.css.width,
1849
+ 'height' : opts.css.height === undefined ? frameHeight + ( $wrap.outerHeight() - $wrap.innerHeight() ) : opts.css.height
1850
+ });
1851
+
1852
+ }
1853
+
1854
+ $wrap.removeClass( 'fancybox-is-hidden' );
1855
+
1856
+ });
1857
+
1858
+ } else {
1859
+
1860
+ this.afterLoad( slide );
1861
+
1862
+ }
1863
+
1864
+ $iframe.attr( 'src', slide.src );
1865
+
1866
+ if ( slide.opts.smallBtn === true ) {
1867
+ slide.$content.prepend( self.translate( slide, slide.opts.btnTpl.smallBtn ) );
1868
+ }
1869
+
1870
+ // Remove iframe if closing or changing gallery item
1871
+ $slide.one( 'onReset', function () {
1872
+
1873
+ // This helps IE not to throw errors when closing
1874
+ try {
1875
+
1876
+ $( this ).find( 'iframe' ).hide().attr( 'src', '//about:blank' );
1877
+
1878
+ } catch ( ignore ) {}
1879
+
1880
+ $( this ).empty();
1881
+
1882
+ slide.isLoaded = false;
1883
+
1884
+ });
1885
+
1886
+ },
1887
+
1888
+
1889
+ // Wrap and append content to the slide
1890
+ // ======================================
1891
+
1892
+ setContent : function ( slide, content ) {
1893
+
1894
+ var self = this;
1895
+
1896
+ if ( self.isClosing ) {
1897
+ return;
1898
+ }
1899
+
1900
+ self.hideLoading( slide );
1901
+
1902
+ slide.$slide.empty();
1903
+
1904
+ if ( isQuery( content ) && content.parent().length ) {
1905
+
1906
+ // If content is a jQuery object, then it will be moved to the slide.
1907
+ // The placeholder is created so we will know where to put it back.
1908
+ // If user is navigating gallery fast, then the content might be already inside fancyBox
1909
+ // =====================================================================================
1910
+
1911
+ // Make sure content is not already moved to fancyBox
1912
+ content.parent( '.fancybox-slide--inline' ).trigger( 'onReset' );
1913
+
1914
+ // Create temporary element marking original place of the content
1915
+ slide.$placeholder = $( '<div></div>' ).hide().insertAfter( content );
1916
+
1917
+ // Make sure content is visible
1918
+ content.css('display', 'inline-block');
1919
+
1920
+ } else if ( !slide.hasError ) {
1921
+
1922
+ // If content is just a plain text, try to convert it to html
1923
+ if ( $.type( content ) === 'string' ) {
1924
+ content = $('<div>').append( $.trim( content ) ).contents();
1925
+
1926
+ // If we have text node, then add wrapping element to make vertical alignment work
1927
+ if ( content[0].nodeType === 3 ) {
1928
+ content = $('<div>').html( content );
1929
+ }
1930
+ }
1931
+
1932
+ // If "filter" option is provided, then filter content
1933
+ if ( slide.opts.filter ) {
1934
+ content = $('<div>').html( content ).find( slide.opts.filter );
1935
+ }
1936
+
1937
+ }
1938
+
1939
+ slide.$slide.one('onReset', function () {
1940
+
1941
+ // Put content back
1942
+ if ( slide.$placeholder ) {
1943
+ slide.$placeholder.after( content.hide() ).remove();
1944
+
1945
+ slide.$placeholder = null;
1946
+ }
1947
+
1948
+ // Remove custom close button
1949
+ if ( slide.$smallBtn ) {
1950
+ slide.$smallBtn.remove();
1951
+
1952
+ slide.$smallBtn = null;
1953
+ }
1954
+
1955
+ // Remove content and mark slide as not loaded
1956
+ if ( !slide.hasError ) {
1957
+ $(this).empty();
1958
+
1959
+ slide.isLoaded = false;
1960
+ }
1961
+
1962
+ });
1963
+
1964
+ slide.$content = $( content ).appendTo( slide.$slide );
1965
+
1966
+ if ( slide.opts.smallBtn && !slide.$smallBtn ) {
1967
+ slide.$smallBtn = $( self.translate( slide, slide.opts.btnTpl.smallBtn ) ).appendTo( slide.$content );
1968
+ }
1969
+
1970
+ this.afterLoad( slide );
1971
+ },
1972
+
1973
+ // Display error message
1974
+ // =====================
1975
+
1976
+ setError : function ( slide ) {
1977
+
1978
+ slide.hasError = true;
1979
+
1980
+ slide.$slide.removeClass( 'fancybox-slide--' + slide.type );
1981
+
1982
+ this.setContent( slide, this.translate( slide, slide.opts.errorTpl ) );
1983
+
1984
+ },
1985
+
1986
+
1987
+ // Show loading icon inside the slide
1988
+ // ==================================
1989
+
1990
+ showLoading : function( slide ) {
1991
+
1992
+ var self = this;
1993
+
1994
+ slide = slide || self.current;
1995
+
1996
+ if ( slide && !slide.$spinner ) {
1997
+ slide.$spinner = $( self.opts.spinnerTpl ).appendTo( slide.$slide );
1998
+ }
1999
+
2000
+ },
2001
+
2002
+ // Remove loading icon from the slide
2003
+ // ==================================
2004
+
2005
+ hideLoading : function( slide ) {
2006
+
2007
+ var self = this;
2008
+
2009
+ slide = slide || self.current;
2010
+
2011
+ if ( slide && slide.$spinner ) {
2012
+ slide.$spinner.remove();
2013
+
2014
+ delete slide.$spinner;
2015
+ }
2016
+
2017
+ },
2018
+
2019
+
2020
+ // Adjustments after slide content has been loaded
2021
+ // ===============================================
2022
+
2023
+ afterLoad : function( slide ) {
2024
+
2025
+ var self = this;
2026
+
2027
+ if ( self.isClosing ) {
2028
+ return;
2029
+ }
2030
+
2031
+ slide.isLoading = false;
2032
+ slide.isLoaded = true;
2033
+
2034
+ self.trigger( 'afterLoad', slide );
2035
+
2036
+ self.hideLoading( slide );
2037
+
2038
+ if ( slide.opts.protect && slide.$content && !slide.hasError ) {
2039
+
2040
+ // Disable right click
2041
+ slide.$content.on( 'contextmenu.fb', function( e ) {
2042
+ if ( e.button == 2 ) {
2043
+ e.preventDefault();
2044
+ }
2045
+
2046
+ return true;
2047
+ });
2048
+
2049
+ // Add fake element on top of the image
2050
+ // This makes a bit harder for user to select image
2051
+ if ( slide.type === 'image' ) {
2052
+ $( '<div class="fancybox-spaceball"></div>' ).appendTo( slide.$content );
2053
+ }
2054
+
2055
+ }
2056
+
2057
+ self.revealContent( slide );
2058
+
2059
+ },
2060
+
2061
+
2062
+ // Make content visible
2063
+ // This method is called right after content has been loaded or
2064
+ // user navigates gallery and transition should start
2065
+ // ============================================================
2066
+
2067
+ revealContent : function( slide ) {
2068
+
2069
+ var self = this;
2070
+ var $slide = slide.$slide;
2071
+
2072
+ var effect, effectClassName, duration, opacity, end, start = false;
2073
+
2074
+ effect = slide.opts[ self.firstRun ? 'animationEffect' : 'transitionEffect' ];
2075
+ duration = slide.opts[ self.firstRun ? 'animationDuration' : 'transitionDuration' ];
2076
+
2077
+ duration = parseInt( slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10 );
2078
+
2079
+ if ( slide.isMoved || slide.pos !== self.currPos || !duration ) {
2080
+ effect = false;
2081
+ }
2082
+
2083
+ // Check if can zoom
2084
+ if ( effect === 'zoom' && !( slide.pos === self.currPos && duration && slide.type === 'image' && !slide.hasError && ( start = self.getThumbPos( slide ) ) ) ) {
2085
+ effect = 'fade';
2086
+ }
2087
+
2088
+
2089
+ // Zoom animation
2090
+ // ==============
2091
+
2092
+ if ( effect === 'zoom' ) {
2093
+ end = self.getFitPos( slide );
2094
+
2095
+ end.scaleX = end.width / start.width;
2096
+ end.scaleY = end.height / start.height;
2097
+
2098
+ delete end.width;
2099
+ delete end.height;
2100
+
2101
+ // Check if we need to animate opacity
2102
+ opacity = slide.opts.zoomOpacity;
2103
+
2104
+ if ( opacity == 'auto' ) {
2105
+ opacity = Math.abs( slide.width / slide.height - start.width / start.height ) > 0.1;
2106
+ }
2107
+
2108
+ if ( opacity ) {
2109
+ start.opacity = 0.1;
2110
+ end.opacity = 1;
2111
+ }
2112
+
2113
+ // Draw image at start position
2114
+ $.fancybox.setTranslate( slide.$content.removeClass( 'fancybox-is-hidden' ), start );
2115
+
2116
+ forceRedraw( slide.$content );
2117
+
2118
+ // Start animation
2119
+ $.fancybox.animate( slide.$content, end, duration, function() {
2120
+ self.complete();
2121
+ });
2122
+
2123
+ return;
2124
+ }
2125
+
2126
+
2127
+ self.updateSlide( slide );
2128
+
2129
+
2130
+ // Simply show content
2131
+ // ===================
2132
+
2133
+ if ( !effect ) {
2134
+ forceRedraw( $slide );
2135
+
2136
+ slide.$content.removeClass( 'fancybox-is-hidden' );
2137
+
2138
+ if ( slide.pos === self.currPos ) {
2139
+ self.complete();
2140
+ }
2141
+
2142
+ return;
2143
+ }
2144
+
2145
+ $.fancybox.stop( $slide );
2146
+
2147
+ effectClassName = 'fancybox-animated fancybox-slide--' + ( slide.pos > self.prevPos ? 'next' : 'previous' ) + ' fancybox-fx-' + effect;
2148
+
2149
+ $slide.removeAttr( 'style' ).removeClass( 'fancybox-slide--current fancybox-slide--next fancybox-slide--previous' ).addClass( effectClassName );
2150
+
2151
+ slide.$content.removeClass( 'fancybox-is-hidden' );
2152
+
2153
+ //Force reflow for CSS3 transitions
2154
+ forceRedraw( $slide );
2155
+
2156
+ $.fancybox.animate( $slide, 'fancybox-slide--current', duration, function(e) {
2157
+ $slide.removeClass( effectClassName ).removeAttr( 'style' );
2158
+
2159
+ if ( slide.pos === self.currPos ) {
2160
+ self.complete();
2161
+ }
2162
+
2163
+ }, true);
2164
+
2165
+ },
2166
+
2167
+
2168
+ // Check if we can and have to zoom from thumbnail
2169
+ //================================================
2170
+
2171
+ getThumbPos : function( slide ) {
2172
+
2173
+ var self = this;
2174
+ var rez = false;
2175
+
2176
+ // Check if element is inside the viewport by at least 1 pixel
2177
+ var isElementVisible = function( $el ) {
2178
+ var element = $el[0];
2179
+
2180
+ var elementRect = element.getBoundingClientRect();
2181
+ var parentRects = [];
2182
+
2183
+ var visibleInAllParents;
2184
+
2185
+ while ( element.parentElement !== null ) {
2186
+ if ( $(element.parentElement).css('overflow') === 'hidden' || $(element.parentElement).css('overflow') === 'auto' ) {
2187
+ parentRects.push(element.parentElement.getBoundingClientRect());
2188
+ }
2189
+
2190
+ element = element.parentElement;
2191
+ }
2192
+
2193
+ visibleInAllParents = parentRects.every(function(parentRect){
2194
+ var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
2195
+ var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
2196
+
2197
+ return visiblePixelX > 0 && visiblePixelY > 0;
2198
+ });
2199
+
2200
+ return visibleInAllParents &&
2201
+ elementRect.bottom > 0 && elementRect.right > 0 &&
2202
+ elementRect.left < $(window).width() && elementRect.top < $(window).height();
2203
+ };
2204
+
2205
+ var $thumb = slide.opts.$thumb;
2206
+ var thumbPos = $thumb ? $thumb.offset() : 0;
2207
+ var slidePos;
2208
+
2209
+ if ( thumbPos && $thumb[0].ownerDocument === document && isElementVisible( $thumb ) ) {
2210
+ slidePos = self.$refs.stage.offset();
2211
+
2212
+ rez = {
2213
+ top : thumbPos.top - slidePos.top + parseFloat( $thumb.css( "border-top-width" ) || 0 ),
2214
+ left : thumbPos.left - slidePos.left + parseFloat( $thumb.css( "border-left-width" ) || 0 ),
2215
+ width : $thumb.width(),
2216
+ height : $thumb.height(),
2217
+ scaleX : 1,
2218
+ scaleY : 1
2219
+ };
2220
+ }
2221
+
2222
+ return rez;
2223
+ },
2224
+
2225
+
2226
+ // Final adjustments after current gallery item is moved to position
2227
+ // and it`s content is loaded
2228
+ // ==================================================================
2229
+
2230
+ complete : function() {
2231
+
2232
+ var self = this;
2233
+
2234
+ var current = self.current;
2235
+ var slides = {};
2236
+
2237
+ if ( current.isMoved || !current.isLoaded || current.isComplete ) {
2238
+ return;
2239
+ }
2240
+
2241
+ current.isComplete = true;
2242
+
2243
+ current.$slide.siblings().trigger( 'onReset' );
2244
+
2245
+ // Trigger any CSS3 transiton inside the slide
2246
+ forceRedraw( current.$slide );
2247
+
2248
+ current.$slide.addClass( 'fancybox-slide--complete' );
2249
+
2250
+ // Remove unnecessary slides
2251
+ $.each( self.slides, function( key, slide ) {
2252
+ if ( slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1 ) {
2253
+ slides[ slide.pos ] = slide;
2254
+
2255
+ } else if ( slide ) {
2256
+
2257
+ $.fancybox.stop( slide.$slide );
2258
+
2259
+ slide.$slide.unbind().remove();
2260
+ }
2261
+ });
2262
+
2263
+ self.slides = slides;
2264
+
2265
+ self.updateCursor();
2266
+
2267
+ self.trigger( 'afterShow' );
2268
+
2269
+ // Try to focus on the first focusable element
2270
+ if ( $( document.activeElement ).is( '[disabled]' ) || ( current.opts.autoFocus && !( current.type == 'image' || current.type === 'iframe' ) ) ) {
2271
+ self.focus();
2272
+ }
2273
+
2274
+ },
2275
+
2276
+
2277
+ // Preload next and previous slides
2278
+ // ================================
2279
+
2280
+ preload : function() {
2281
+ var self = this;
2282
+ var next, prev;
2283
+
2284
+ if ( self.group.length < 2 ) {
2285
+ return;
2286
+ }
2287
+
2288
+ next = self.slides[ self.currPos + 1 ];
2289
+ prev = self.slides[ self.currPos - 1 ];
2290
+
2291
+ if ( next && next.type === 'image' ) {
2292
+ self.loadSlide( next );
2293
+ }
2294
+
2295
+ if ( prev && prev.type === 'image' ) {
2296
+ self.loadSlide( prev );
2297
+ }
2298
+
2299
+ },
2300
+
2301
+
2302
+ // Try to find and focus on the first focusable element
2303
+ // ====================================================
2304
+
2305
+ focus : function() {
2306
+ var current = this.current;
2307
+ var $el;
2308
+
2309
+ if ( this.isClosing ) {
2310
+ return;
2311
+ }
2312
+
2313
+ // Skip for images and iframes
2314
+ $el = current && current.isComplete ? current.$slide.find('button,:input,[tabindex],a').filter(':not([disabled]):visible:first') : null;
2315
+ $el = $el && $el.length ? $el : this.$refs.container;
2316
+
2317
+ $el.focus();
2318
+ },
2319
+
2320
+
2321
+ // Activates current instance - brings container to the front and enables keyboard,
2322
+ // notifies other instances about deactivating
2323
+ // =================================================================================
2324
+
2325
+ activate : function () {
2326
+ var self = this;
2327
+
2328
+ // Deactivate all instances
2329
+ $( '.fancybox-container' ).each(function () {
2330
+ var instance = $(this).data( 'FancyBox' );
2331
+
2332
+ // Skip self and closing instances
2333
+ if (instance && instance.uid !== self.uid && !instance.isClosing) {
2334
+ instance.trigger( 'onDeactivate' );
2335
+ }
2336
+
2337
+ });
2338
+
2339
+ if ( self.current ) {
2340
+ if ( self.$refs.container.index() > 0 ) {
2341
+ self.$refs.container.prependTo( document.body );
2342
+ }
2343
+
2344
+ self.updateControls();
2345
+ }
2346
+
2347
+ self.trigger( 'onActivate' );
2348
+
2349
+ self.addEvents();
2350
+
2351
+ },
2352
+
2353
+
2354
+ // Start closing procedure
2355
+ // This will start "zoom-out" animation if needed and clean everything up afterwards
2356
+ // =================================================================================
2357
+
2358
+ close : function( e, d ) {
2359
+
2360
+ var self = this;
2361
+ var current = self.current;
2362
+
2363
+ var effect, duration;
2364
+ var $what, opacity, start, end;
2365
+
2366
+ var done = function() {
2367
+ self.cleanUp( e );
2368
+ };
2369
+
2370
+ if ( self.isClosing ) {
2371
+ return false;
2372
+ }
2373
+
2374
+ self.isClosing = true;
2375
+
2376
+ // If beforeClose callback prevents closing, make sure content is centered
2377
+ if ( self.trigger( 'beforeClose', e ) === false ) {
2378
+ self.isClosing = false;
2379
+
2380
+ requestAFrame(function() {
2381
+ self.update();
2382
+ });
2383
+
2384
+ return false;
2385
+ }
2386
+
2387
+ // Remove all events
2388
+ // If there are multiple instances, they will be set again by "activate" method
2389
+ self.removeEvents();
2390
+
2391
+ if ( current.timouts ) {
2392
+ clearTimeout( current.timouts );
2393
+ }
2394
+
2395
+ $what = current.$content;
2396
+ effect = current.opts.animationEffect;
2397
+ duration = $.isNumeric( d ) ? d : ( effect ? current.opts.animationDuration : 0 );
2398
+
2399
+ // Remove other slides
2400
+ current.$slide.off( transitionEnd ).removeClass( 'fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated' );
2401
+
2402
+ current.$slide.siblings().trigger( 'onReset' ).remove();
2403
+
2404
+ // Trigger animations
2405
+ if ( duration ) {
2406
+ self.$refs.container.removeClass( 'fancybox-is-open' ).addClass( 'fancybox-is-closing' );
2407
+ }
2408
+
2409
+ // Clean up
2410
+ self.hideLoading( current );
2411
+
2412
+ self.hideControls();
2413
+
2414
+ self.updateCursor();
2415
+
2416
+ // Check if possible to zoom-out
2417
+ if ( effect === 'zoom' && !( e !== true && $what && duration && current.type === 'image' && !current.hasError && ( end = self.getThumbPos( current ) ) ) ) {
2418
+ effect = 'fade';
2419
+ }
2420
+
2421
+ if ( effect === 'zoom' ) {
2422
+ $.fancybox.stop( $what );
2423
+
2424
+ start = $.fancybox.getTranslate( $what );
2425
+
2426
+ start.width = start.width * start.scaleX;
2427
+ start.height = start.height * start.scaleY;
2428
+
2429
+ // Check if we need to animate opacity
2430
+ opacity = current.opts.zoomOpacity;
2431
+
2432
+ if ( opacity == 'auto' ) {
2433
+ opacity = Math.abs( current.width / current.height - end.width / end.height ) > 0.1;
2434
+ }
2435
+
2436
+ if ( opacity ) {
2437
+ end.opacity = 0;
2438
+ }
2439
+
2440
+ start.scaleX = start.width / end.width;
2441
+ start.scaleY = start.height / end.height;
2442
+
2443
+ start.width = end.width;
2444
+ start.height = end.height;
2445
+
2446
+ $.fancybox.setTranslate( current.$content, start );
2447
+
2448
+ $.fancybox.animate( current.$content, end, duration, done );
2449
+
2450
+ return true;
2451
+ }
2452
+
2453
+ if ( effect && duration ) {
2454
+
2455
+ // If skip animation
2456
+ if ( e === true ) {
2457
+ setTimeout( done, duration );
2458
+
2459
+ } else {
2460
+ $.fancybox.animate( current.$slide.removeClass( 'fancybox-slide--current' ), 'fancybox-animated fancybox-slide--previous fancybox-fx-' + effect, duration, done );
2461
+ }
2462
+
2463
+ } else {
2464
+ done();
2465
+ }
2466
+
2467
+ return true;
2468
+ },
2469
+
2470
+
2471
+ // Final adjustments after removing the instance
2472
+ // =============================================
2473
+
2474
+ cleanUp : function( e ) {
2475
+ var self = this,
2476
+ instance;
2477
+
2478
+ self.current.$slide.trigger( 'onReset' );
2479
+
2480
+ self.$refs.container.empty().remove();
2481
+
2482
+ self.trigger( 'afterClose', e );
2483
+
2484
+ // Place back focus
2485
+ if ( self.$lastFocus && !!self.current.opts.backFocus ) {
2486
+ self.$lastFocus.focus();
2487
+ }
2488
+
2489
+ self.current = null;
2490
+
2491
+ // Check if there are other instances
2492
+ instance = $.fancybox.getInstance();
2493
+
2494
+ if ( instance ) {
2495
+ instance.activate();
2496
+
2497
+ } else {
2498
+
2499
+ $W.scrollTop( self.scrollTop ).scrollLeft( self.scrollLeft );
2500
+
2501
+ $( 'html' ).removeClass( 'fancybox-enabled' );
2502
+
2503
+ $( '#fancybox-style-noscroll' ).remove();
2504
+ }
2505
+
2506
+ },
2507
+
2508
+
2509
+ // Call callback and trigger an event
2510
+ // ==================================
2511
+
2512
+ trigger : function( name, slide ) {
2513
+ var args = Array.prototype.slice.call(arguments, 1),
2514
+ self = this,
2515
+ obj = slide && slide.opts ? slide : self.current,
2516
+ rez;
2517
+
2518
+ if ( obj ) {
2519
+ args.unshift( obj );
2520
+
2521
+ } else {
2522
+ obj = self;
2523
+ }
2524
+
2525
+ args.unshift( self );
2526
+
2527
+ if ( $.isFunction( obj.opts[ name ] ) ) {
2528
+ rez = obj.opts[ name ].apply( obj, args );
2529
+ }
2530
+
2531
+ if ( rez === false ) {
2532
+ return rez;
2533
+ }
2534
+
2535
+ if ( name === 'afterClose' ) {
2536
+ $D.trigger( name + '.fb', args );
2537
+
2538
+ } else {
2539
+ self.$refs.container.trigger( name + '.fb', args );
2540
+ }
2541
+
2542
+ },
2543
+
2544
+
2545
+ // Update infobar values, navigation button states and reveal caption
2546
+ // ==================================================================
2547
+
2548
+ updateControls : function ( force ) {
2549
+
2550
+ var self = this;
2551
+
2552
+ var current = self.current;
2553
+ var index = current.index;
2554
+ var opts = current.opts;
2555
+ var caption = opts.caption;
2556
+ var $caption = self.$refs.caption;
2557
+
2558
+ // Recalculate content dimensions
2559
+ current.$slide.trigger( 'refresh' );
2560
+
2561
+ self.$caption = caption && caption.length ? $caption.html( caption ) : null;
2562
+
2563
+ if ( !self.isHiddenControls ) {
2564
+ self.showControls();
2565
+ }
2566
+
2567
+ // Update info and navigation elements
2568
+ $('[data-fancybox-count]').html( self.group.length );
2569
+ $('[data-fancybox-index]').html( index + 1 );
2570
+
2571
+ $('[data-fancybox-prev]').prop('disabled', ( !opts.loop && index <= 0 ) );
2572
+ $('[data-fancybox-next]').prop('disabled', ( !opts.loop && index >= self.group.length - 1 ) );
2573
+
2574
+ },
2575
+
2576
+ // Hide toolbar and caption
2577
+ // ========================
2578
+
2579
+ hideControls : function () {
2580
+
2581
+ this.isHiddenControls = true;
2582
+
2583
+ this.$refs.container.removeClass('fancybox-show-infobar fancybox-show-toolbar fancybox-show-caption fancybox-show-nav');
2584
+
2585
+ },
2586
+
2587
+ showControls : function() {
2588
+
2589
+ var self = this;
2590
+ var opts = self.current ? self.current.opts : self.opts;
2591
+ var $container = self.$refs.container;
2592
+
2593
+ self.isHiddenControls = false;
2594
+ self.idleSecondsCounter = 0;
2595
+
2596
+ $container
2597
+ .toggleClass('fancybox-show-toolbar', !!( opts.toolbar && opts.buttons ) )
2598
+ .toggleClass('fancybox-show-infobar', !!( opts.infobar && self.group.length > 1 ) )
2599
+ .toggleClass('fancybox-show-nav', !!( opts.arrows && self.group.length > 1 ) )
2600
+ .toggleClass('fancybox-is-modal', !!opts.modal );
2601
+
2602
+ if ( self.$caption ) {
2603
+ $container.addClass( 'fancybox-show-caption ');
2604
+
2605
+ } else {
2606
+ $container.removeClass( 'fancybox-show-caption' );
2607
+ }
2608
+
2609
+ },
2610
+
2611
+
2612
+ // Toggle toolbar and caption
2613
+ // ==========================
2614
+
2615
+ toggleControls : function() {
2616
+
2617
+ if ( this.isHiddenControls ) {
2618
+ this.showControls();
2619
+
2620
+ } else {
2621
+ this.hideControls();
2622
+ }
2623
+
2624
+ },
2625
+
2626
+
2627
+ });
2628
+
2629
+
2630
+ $.fancybox = {
2631
+
2632
+ version : "3.1.24",
2633
+ defaults : defaults,
2634
+
2635
+
2636
+ // Get current instance and execute a command.
2637
+ //
2638
+ // Examples of usage:
2639
+ //
2640
+ // $instance = $.fancybox.getInstance();
2641
+ // $.fancybox.getInstance().jumpTo( 1 );
2642
+ // $.fancybox.getInstance( 'jumpTo', 1 );
2643
+ // $.fancybox.getInstance( function() {
2644
+ // console.info( this.currIndex );
2645
+ // });
2646
+ // ======================================================
2647
+
2648
+ getInstance : function ( command ) {
2649
+ var instance = $('.fancybox-container:not(".fancybox-is-closing"):first').data( 'FancyBox' );
2650
+ var args = Array.prototype.slice.call(arguments, 1);
2651
+
2652
+ if ( instance instanceof FancyBox ) {
2653
+
2654
+ if ( $.type( command ) === 'string' ) {
2655
+ instance[ command ].apply( instance, args );
2656
+
2657
+ } else if ( $.type( command ) === 'function' ) {
2658
+ command.apply( instance, args );
2659
+
2660
+ }
2661
+
2662
+ return instance;
2663
+ }
2664
+
2665
+ return false;
2666
+
2667
+ },
2668
+
2669
+
2670
+ // Create new instance
2671
+ // ===================
2672
+
2673
+ open : function ( items, opts, index ) {
2674
+ return new FancyBox( items, opts, index );
2675
+ },
2676
+
2677
+
2678
+ // Close current or all instances
2679
+ // ==============================
2680
+
2681
+ close : function ( all ) {
2682
+ var instance = this.getInstance();
2683
+
2684
+ if ( instance ) {
2685
+ instance.close();
2686
+
2687
+ // Try to find and close next instance
2688
+
2689
+ if ( all === true ) {
2690
+ this.close();
2691
+ }
2692
+ }
2693
+
2694
+ },
2695
+
2696
+ // Close instances and unbind all events
2697
+ // ==============================
2698
+
2699
+ destroy : function() {
2700
+
2701
+ this.close( true );
2702
+
2703
+ $D.off( 'click.fb-start' );
2704
+
2705
+ },
2706
+
2707
+
2708
+ // Try to detect mobile devices
2709
+ // ============================
2710
+
2711
+ isMobile : document.createTouch !== undefined && /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent),
2712
+
2713
+
2714
+ // Detect if 'translate3d' support is available
2715
+ // ============================================
2716
+
2717
+ use3d : (function() {
2718
+ var div = document.createElement('div');
2719
+
2720
+ return window.getComputedStyle && window.getComputedStyle( div ).getPropertyValue('transform') && !(document.documentMode && document.documentMode < 11);
2721
+ }()),
2722
+
2723
+
2724
+ // Helper function to get current visual state of an element
2725
+ // returns array[ top, left, horizontal-scale, vertical-scale, opacity ]
2726
+ // =====================================================================
2727
+
2728
+ getTranslate : function( $el ) {
2729
+ var matrix;
2730
+
2731
+ if ( !$el || !$el.length ) {
2732
+ return false;
2733
+ }
2734
+
2735
+ matrix = $el.eq( 0 ).css('transform');
2736
+
2737
+ if ( matrix && matrix.indexOf( 'matrix' ) !== -1 ) {
2738
+ matrix = matrix.split('(')[1];
2739
+ matrix = matrix.split(')')[0];
2740
+ matrix = matrix.split(',');
2741
+ } else {
2742
+ matrix = [];
2743
+ }
2744
+
2745
+ if ( matrix.length ) {
2746
+
2747
+ // If IE
2748
+ if ( matrix.length > 10 ) {
2749
+ matrix = [ matrix[13], matrix[12], matrix[0], matrix[5] ];
2750
+
2751
+ } else {
2752
+ matrix = [ matrix[5], matrix[4], matrix[0], matrix[3]];
2753
+ }
2754
+
2755
+ matrix = matrix.map(parseFloat);
2756
+
2757
+ } else {
2758
+ matrix = [ 0, 0, 1, 1 ];
2759
+
2760
+ var transRegex = /\.*translate\((.*)px,(.*)px\)/i;
2761
+ var transRez = transRegex.exec( $el.eq( 0 ).attr('style') );
2762
+
2763
+ if ( transRez ) {
2764
+ matrix[ 0 ] = parseFloat( transRez[2] );
2765
+ matrix[ 1 ] = parseFloat( transRez[1] );
2766
+ }
2767
+ }
2768
+
2769
+ return {
2770
+ top : matrix[ 0 ],
2771
+ left : matrix[ 1 ],
2772
+ scaleX : matrix[ 2 ],
2773
+ scaleY : matrix[ 3 ],
2774
+ opacity : parseFloat( $el.css('opacity') ),
2775
+ width : $el.width(),
2776
+ height : $el.height()
2777
+ };
2778
+
2779
+ },
2780
+
2781
+
2782
+ // Shortcut for setting "translate3d" properties for element
2783
+ // Can set be used to set opacity, too
2784
+ // ========================================================
2785
+
2786
+ setTranslate : function( $el, props ) {
2787
+ var str = '';
2788
+ var css = {};
2789
+
2790
+ if ( !$el || !props ) {
2791
+ return;
2792
+ }
2793
+
2794
+ if ( props.left !== undefined || props.top !== undefined ) {
2795
+ str = ( props.left === undefined ? $el.position().left : props.left ) + 'px, ' + ( props.top === undefined ? $el.position().top : props.top ) + 'px';
2796
+
2797
+ if ( this.use3d ) {
2798
+ str = 'translate3d(' + str + ', 0px)';
2799
+
2800
+ } else {
2801
+ str = 'translate(' + str + ')';
2802
+ }
2803
+ }
2804
+
2805
+ if ( props.scaleX !== undefined && props.scaleY !== undefined ) {
2806
+ str = (str.length ? str + ' ' : '') + 'scale(' + props.scaleX + ', ' + props.scaleY + ')';
2807
+ }
2808
+
2809
+ if ( str.length ) {
2810
+ css.transform = str;
2811
+ }
2812
+
2813
+ if ( props.opacity !== undefined ) {
2814
+ css.opacity = props.opacity;
2815
+ }
2816
+
2817
+ if ( props.width !== undefined ) {
2818
+ css.width = props.width;
2819
+ }
2820
+
2821
+ if ( props.height !== undefined ) {
2822
+ css.height = props.height;
2823
+ }
2824
+
2825
+ return $el.css( css );
2826
+ },
2827
+
2828
+
2829
+ // Simple CSS transition handler
2830
+ // =============================
2831
+
2832
+ animate : function ( $el, to, duration, callback, leaveAnimationName ) {
2833
+ var event = transitionEnd || 'transitionend';
2834
+
2835
+ if ( $.isFunction( duration ) ) {
2836
+ callback = duration;
2837
+ duration = null;
2838
+ }
2839
+
2840
+ if ( !$.isPlainObject( to ) ) {
2841
+ $el.removeAttr('style');
2842
+ }
2843
+
2844
+ $el.on( event, function(e) {
2845
+
2846
+ // Skip events from child elements and z-index change
2847
+ if ( e && e.originalEvent && ( !$el.is( e.originalEvent.target ) || e.originalEvent.propertyName == 'z-index' ) ) {
2848
+ return;
2849
+ }
2850
+
2851
+ $el.off( event );
2852
+
2853
+ if ( $.isPlainObject( to ) ) {
2854
+
2855
+ if ( to.scaleX !== undefined && to.scaleY !== undefined ) {
2856
+ $el.css( 'transition-duration', '0ms' );
2857
+
2858
+ to.width = Math.round( $el.width() * to.scaleX );
2859
+ to.height = Math.round( $el.height() * to.scaleY );
2860
+
2861
+ to.scaleX = 1;
2862
+ to.scaleY = 1;
2863
+
2864
+ $.fancybox.setTranslate( $el, to );
2865
+ }
2866
+
2867
+ } else if ( leaveAnimationName !== true ) {
2868
+ $el.removeClass( to );
2869
+ }
2870
+
2871
+ if ( $.isFunction( callback ) ) {
2872
+ callback( e );
2873
+ }
2874
+
2875
+ });
2876
+
2877
+ if ( $.isNumeric( duration ) ) {
2878
+ $el.css( 'transition-duration', duration + 'ms' );
2879
+ }
2880
+
2881
+ if ( $.isPlainObject( to ) ) {
2882
+ $.fancybox.setTranslate( $el, to );
2883
+
2884
+ } else {
2885
+ $el.addClass( to );
2886
+ }
2887
+
2888
+ $el.data("timer", setTimeout(function() {
2889
+ $el.trigger( 'transitionend' );
2890
+ }, duration + 16));
2891
+
2892
+ },
2893
+
2894
+ stop : function( $el ) {
2895
+ clearTimeout( $el.data("timer") );
2896
+
2897
+ $el.off( transitionEnd );
2898
+ }
2899
+
2900
+ };
2901
+
2902
+
2903
+ // Default click handler for "fancyboxed" links
2904
+ // ============================================
2905
+
2906
+ function _run( e ) {
2907
+ var target = e.currentTarget,
2908
+ opts = e.data ? e.data.options : {},
2909
+ items = opts.selector ? $( opts.selector ) : ( e.data ? e.data.items : [] ),
2910
+ value = $(target).attr( 'data-fancybox' ) || '',
2911
+ index = 0,
2912
+ active = $.fancybox.getInstance();
2913
+
2914
+ e.preventDefault();
2915
+ e.stopPropagation();
2916
+
2917
+ // Avoid opening multiple times
2918
+ if ( active && active.current.opts.$orig.is( target ) ) {
2919
+ return;
2920
+ }
2921
+
2922
+ // Get all related items and find index for clicked one
2923
+ if ( value ) {
2924
+ items = items.length ? items.filter( '[data-fancybox="' + value + '"]' ) : $( '[data-fancybox="' + value + '"]' );
2925
+ index = items.index( target );
2926
+
2927
+ // Sometimes current item can not be found
2928
+ // (for example, when slider clones items)
2929
+ if ( index < 0 ) {
2930
+ index = 0;
2931
+ }
2932
+
2933
+ } else {
2934
+ items = [ target ];
2935
+ }
2936
+
2937
+ $.fancybox.open( items, opts, index );
2938
+ }
2939
+
2940
+
2941
+ // Create a jQuery plugin
2942
+ // ======================
2943
+
2944
+ $.fn.fancybox = function (options) {
2945
+ var selector;
2946
+
2947
+ options = options || {};
2948
+ selector = options.selector || false;
2949
+
2950
+ if ( selector ) {
2951
+
2952
+ $( 'body' ).off( 'click.fb-start', selector ).on( 'click.fb-start', selector, {
2953
+ options : options
2954
+ }, _run );
2955
+
2956
+ } else {
2957
+
2958
+ this.off( 'click.fb-start' ).on( 'click.fb-start', {
2959
+ items : this,
2960
+ options : options
2961
+ }, _run);
2962
+
2963
+ }
2964
+
2965
+ return this;
2966
+ };
2967
+
2968
+
2969
+ // Self initializing plugin
2970
+ // ========================
2971
+
2972
+ $D.on( 'click.fb-start', '[data-fancybox]', _run );
2973
+
2974
+ }( window, document, window.jQuery ));
2975
+
2976
+ // ==========================================================================
2977
+ //
2978
+ // Media
2979
+ // Adds additional media type support
2980
+ //
2981
+ // ==========================================================================
2982
+ ;(function ($) {
2983
+
2984
+ 'use strict';
2985
+
2986
+ // Formats matching url to final form
2987
+
2988
+ var format = function (url, rez, params) {
2989
+ if ( !url ) {
2990
+ return;
2991
+ }
2992
+
2993
+ params = params || '';
2994
+
2995
+ if ( $.type(params) === "object" ) {
2996
+ params = $.param(params, true);
2997
+ }
2998
+
2999
+ $.each(rez, function (key, value) {
3000
+ url = url.replace('$' + key, value || '');
3001
+ });
3002
+
3003
+ if (params.length) {
3004
+ url += (url.indexOf('?') > 0 ? '&' : '?') + params;
3005
+ }
3006
+
3007
+ return url;
3008
+ };
3009
+
3010
+ // Object containing properties for each media type
3011
+
3012
+ var defaults = {
3013
+ youtube : {
3014
+ matcher : /(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i,
3015
+ params : {
3016
+ autoplay : 1,
3017
+ autohide : 1,
3018
+ fs : 1,
3019
+ rel : 0,
3020
+ hd : 1,
3021
+ wmode : 'transparent',
3022
+ enablejsapi : 1,
3023
+ html5 : 1
3024
+ },
3025
+ paramPlace : 8,
3026
+ type : 'iframe',
3027
+ url : '//www.youtube.com/embed/$4',
3028
+ thumb : '//img.youtube.com/vi/$4/hqdefault.jpg'
3029
+ },
3030
+
3031
+ vimeo : {
3032
+ matcher : /^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/,
3033
+ params : {
3034
+ autoplay : 1,
3035
+ hd : 1,
3036
+ show_title : 1,
3037
+ show_byline : 1,
3038
+ show_portrait : 0,
3039
+ fullscreen : 1,
3040
+ api : 1
3041
+ },
3042
+ paramPlace : 3,
3043
+ type : 'iframe',
3044
+ url : '//player.vimeo.com/video/$2'
3045
+ },
3046
+
3047
+ metacafe : {
3048
+ matcher : /metacafe.com\/watch\/(\d+)\/(.*)?/,
3049
+ type : 'iframe',
3050
+ url : '//www.metacafe.com/embed/$1/?ap=1'
3051
+ },
3052
+
3053
+ dailymotion : {
3054
+ matcher : /dailymotion.com\/video\/(.*)\/?(.*)/,
3055
+ params : {
3056
+ additionalInfos : 0,
3057
+ autoStart : 1
3058
+ },
3059
+ type : 'iframe',
3060
+ url : '//www.dailymotion.com/embed/video/$1'
3061
+ },
3062
+
3063
+ vine : {
3064
+ matcher : /vine.co\/v\/([a-zA-Z0-9\?\=\-]+)/,
3065
+ type : 'iframe',
3066
+ url : '//vine.co/v/$1/embed/simple'
3067
+ },
3068
+
3069
+ instagram : {
3070
+ matcher : /(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i,
3071
+ type : 'image',
3072
+ url : '//$1/p/$2/media/?size=l'
3073
+ },
3074
+
3075
+ // Examples:
3076
+ // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16
3077
+ // https://www.google.com/maps/@37.7852006,-122.4146355,14.65z
3078
+ // https://www.google.com/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572
3079
+ gmap_place : {
3080
+ matcher : /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?\@(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i,
3081
+ type : 'iframe',
3082
+ url : function (rez) {
3083
+ return '//maps.google.' + rez[2] + '/?ll=' + ( rez[9] ? rez[9] + '&z=' + Math.floor( rez[10] ) + ( rez[12] ? rez[12].replace(/^\//, "&") : '' ) : rez[12] ) + '&output=' + ( rez[12] && rez[12].indexOf('layer=c') > 0 ? 'svembed' : 'embed' );
3084
+ }
3085
+ },
3086
+
3087
+ // Examples:
3088
+ // https://www.google.com/maps/search/Empire+State+Building/
3089
+ // https://www.google.com/maps/search/?api=1&query=centurylink+field
3090
+ // https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393
3091
+ gmap_search : {
3092
+ matcher : /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(maps\/search\/)(.*)/i,
3093
+ type : 'iframe',
3094
+ url : function (rez) {
3095
+ return '//maps.google.' + rez[2] + '/maps?q=' + rez[5].replace('query=', 'q=').replace('api=1', '') + '&output=embed';
3096
+ }
3097
+ }
3098
+ };
3099
+
3100
+ $(document).on('onInit.fb', function (e, instance) {
3101
+
3102
+ $.each(instance.group, function( i, item ) {
3103
+
3104
+ var url = item.src || '',
3105
+ type = false,
3106
+ media,
3107
+ thumb,
3108
+ rez,
3109
+ params,
3110
+ urlParams,
3111
+ o,
3112
+ provider;
3113
+
3114
+ // Skip items that already have content type
3115
+ if ( item.type ) {
3116
+ return;
3117
+ }
3118
+
3119
+ media = $.extend( true, {}, defaults, item.opts.media );
3120
+
3121
+ // Look for any matching media type
3122
+ $.each(media, function ( n, el ) {
3123
+ rez = url.match(el.matcher);
3124
+ o = {};
3125
+ provider = n;
3126
+
3127
+ if (!rez) {
3128
+ return;
3129
+ }
3130
+
3131
+ type = el.type;
3132
+
3133
+ if ( el.paramPlace && rez[ el.paramPlace ] ) {
3134
+ urlParams = rez[ el.paramPlace ];
3135
+
3136
+ if ( urlParams[ 0 ] == '?' ) {
3137
+ urlParams = urlParams.substring(1);
3138
+ }
3139
+
3140
+ urlParams = urlParams.split('&');
3141
+
3142
+ for ( var m = 0; m < urlParams.length; ++m ) {
3143
+ var p = urlParams[ m ].split('=', 2);
3144
+
3145
+ if ( p.length == 2 ) {
3146
+ o[ p[0] ] = decodeURIComponent( p[1].replace(/\+/g, " ") );
3147
+ }
3148
+ }
3149
+ }
3150
+
3151
+ params = $.extend( true, {}, el.params, item.opts[ n ], o );
3152
+
3153
+ url = $.type(el.url) === "function" ? el.url.call(this, rez, params, item) : format(el.url, rez, params);
3154
+ thumb = $.type(el.thumb) === "function" ? el.thumb.call(this, rez, params, item) : format(el.thumb, rez);
3155
+
3156
+ if ( provider === 'vimeo' ) {
3157
+ url = url.replace('&%23', '#');
3158
+ }
3159
+
3160
+ return false;
3161
+ });
3162
+
3163
+ // If it is found, then change content type and update the url
3164
+
3165
+ if ( type ) {
3166
+ item.src = url;
3167
+ item.type = type;
3168
+
3169
+ if ( !item.opts.thumb && !( item.opts.$thumb && item.opts.$thumb.length ) ) {
3170
+ item.opts.thumb = thumb;
3171
+ }
3172
+
3173
+ if ( type === 'iframe' ) {
3174
+ $.extend(true, item.opts, {
3175
+ iframe : {
3176
+ preload : false,
3177
+ attr : {
3178
+ scrolling : "no"
3179
+ }
3180
+ }
3181
+ });
3182
+
3183
+ item.contentProvider = provider;
3184
+
3185
+ item.opts.slideClass += ' fancybox-slide--' + ( provider == 'gmap_place' || provider == 'gmap_search' ? 'map' : 'video' );
3186
+ }
3187
+
3188
+ } else {
3189
+
3190
+ // If no content type is found, then set it to `image` as fallback
3191
+ item.type = 'image';
3192
+ }
3193
+
3194
+ });
3195
+
3196
+ });
3197
+
3198
+ }(window.jQuery));
3199
+
3200
+ // ==========================================================================
3201
+ //
3202
+ // Guestures
3203
+ // Adds touch guestures, handles click and tap events
3204
+ //
3205
+ // ==========================================================================
3206
+ ;(function (window, document, $) {
3207
+ 'use strict';
3208
+
3209
+ var requestAFrame = (function () {
3210
+ return window.requestAnimationFrame ||
3211
+ window.webkitRequestAnimationFrame ||
3212
+ window.mozRequestAnimationFrame ||
3213
+ window.oRequestAnimationFrame ||
3214
+ // if all else fails, use setTimeout
3215
+ function (callback) {
3216
+ return window.setTimeout(callback, 1000 / 60);
3217
+ };
3218
+ })();
3219
+
3220
+
3221
+ var cancelAFrame = (function () {
3222
+ return window.cancelAnimationFrame ||
3223
+ window.webkitCancelAnimationFrame ||
3224
+ window.mozCancelAnimationFrame ||
3225
+ window.oCancelAnimationFrame ||
3226
+ function (id) {
3227
+ window.clearTimeout(id);
3228
+ };
3229
+ })();
3230
+
3231
+
3232
+ var pointers = function( e ) {
3233
+ var result = [];
3234
+
3235
+ e = e.originalEvent || e || window.e;
3236
+ e = e.touches && e.touches.length ? e.touches : ( e.changedTouches && e.changedTouches.length ? e.changedTouches : [ e ] );
3237
+
3238
+ for ( var key in e ) {
3239
+
3240
+ if ( e[ key ].pageX ) {
3241
+ result.push( { x : e[ key ].pageX, y : e[ key ].pageY } );
3242
+
3243
+ } else if ( e[ key ].clientX ) {
3244
+ result.push( { x : e[ key ].clientX, y : e[ key ].clientY } );
3245
+ }
3246
+ }
3247
+
3248
+ return result;
3249
+ };
3250
+
3251
+ var distance = function( point2, point1, what ) {
3252
+ if ( !point1 || !point2 ) {
3253
+ return 0;
3254
+ }
3255
+
3256
+ if ( what === 'x' ) {
3257
+ return point2.x - point1.x;
3258
+
3259
+ } else if ( what === 'y' ) {
3260
+ return point2.y - point1.y;
3261
+ }
3262
+
3263
+ return Math.sqrt( Math.pow( point2.x - point1.x, 2 ) + Math.pow( point2.y - point1.y, 2 ) );
3264
+ };
3265
+
3266
+ var isClickable = function( $el ) {
3267
+ if ( $el.is('a,button,input,select,textarea') || $.isFunction( $el.get(0).onclick ) ) {
3268
+ return true;
3269
+ }
3270
+
3271
+ // Check for attributes like data-fancybox-next or data-fancybox-close
3272
+ for ( var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++ ) {
3273
+ if ( atts[i].nodeName.substr(0, 14) === 'data-fancybox-' ) {
3274
+ return true;
3275
+ }
3276
+ }
3277
+
3278
+ return false;
3279
+ };
3280
+
3281
+ var hasScrollbars = function( el ) {
3282
+ var overflowY = window.getComputedStyle( el )['overflow-y'];
3283
+ var overflowX = window.getComputedStyle( el )['overflow-x'];
3284
+
3285
+ var vertical = (overflowY === 'scroll' || overflowY === 'auto') && el.scrollHeight > el.clientHeight;
3286
+ var horizontal = (overflowX === 'scroll' || overflowX === 'auto') && el.scrollWidth > el.clientWidth;
3287
+
3288
+ return vertical || horizontal;
3289
+ };
3290
+
3291
+ var isScrollable = function ( $el ) {
3292
+ var rez = false;
3293
+
3294
+ while ( true ) {
3295
+ rez = hasScrollbars( $el.get(0) );
3296
+
3297
+ if ( rez ) {
3298
+ break;
3299
+ }
3300
+
3301
+ $el = $el.parent();
3302
+
3303
+ if ( !$el.length || $el.hasClass( 'fancybox-stage' ) || $el.is( 'body' ) ) {
3304
+ break;
3305
+ }
3306
+ }
3307
+
3308
+ return rez;
3309
+ };
3310
+
3311
+
3312
+ var Guestures = function ( instance ) {
3313
+ var self = this;
3314
+
3315
+ self.instance = instance;
3316
+
3317
+ self.$bg = instance.$refs.bg;
3318
+ self.$stage = instance.$refs.stage;
3319
+ self.$container = instance.$refs.container;
3320
+
3321
+ self.destroy();
3322
+
3323
+ self.$container.on( 'touchstart.fb.touch mousedown.fb.touch', $.proxy(self, 'ontouchstart') );
3324
+ };
3325
+
3326
+ Guestures.prototype.destroy = function() {
3327
+ this.$container.off( '.fb.touch' );
3328
+ };
3329
+
3330
+ Guestures.prototype.ontouchstart = function( e ) {
3331
+ var self = this;
3332
+
3333
+ var $target = $( e.target );
3334
+ var instance = self.instance;
3335
+ var current = instance.current;
3336
+ var $content = current.$content;
3337
+
3338
+ var isTouchDevice = ( e.type == 'touchstart' );
3339
+
3340
+ // Do not respond to both events
3341
+ if ( isTouchDevice ) {
3342
+ self.$container.off( 'mousedown.fb.touch' );
3343
+ }
3344
+
3345
+ // Ignore clicks while zooming or closing
3346
+ if ( !current || self.instance.isAnimating || self.instance.isClosing ) {
3347
+ e.stopPropagation();
3348
+ e.preventDefault();
3349
+
3350
+ return;
3351
+ }
3352
+
3353
+ // Ignore right click
3354
+ if ( e.originalEvent && e.originalEvent.button == 2 ) {
3355
+ return;
3356
+ }
3357
+
3358
+ // Ignore taping on links, buttons, input elements
3359
+ if ( !$target.length || isClickable( $target ) || isClickable( $target.parent() ) ) {
3360
+ return;
3361
+ }
3362
+
3363
+ // Ignore clicks on the scrollbar
3364
+ if ( e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left ) {
3365
+ return;
3366
+ }
3367
+
3368
+ self.startPoints = pointers( e );
3369
+
3370
+ // Prevent zooming if already swiping
3371
+ if ( !self.startPoints || ( self.startPoints.length > 1 && instance.isSliding ) ) {
3372
+ return;
3373
+ }
3374
+
3375
+ self.$target = $target;
3376
+ self.$content = $content;
3377
+ self.canTap = true;
3378
+
3379
+ $(document).off( '.fb.touch' );
3380
+
3381
+ $(document).on( isTouchDevice ? 'touchend.fb.touch touchcancel.fb.touch' : 'mouseup.fb.touch mouseleave.fb.touch', $.proxy(self, "ontouchend"));
3382
+ $(document).on( isTouchDevice ? 'touchmove.fb.touch' : 'mousemove.fb.touch', $.proxy(self, "ontouchmove"));
3383
+
3384
+ e.stopPropagation();
3385
+
3386
+ if ( !(instance.current.opts.touch || instance.canPan() ) || !( $target.is( self.$stage ) || self.$stage.find( $target ).length ) ) {
3387
+
3388
+ // Prevent ghosting
3389
+ if ( $target.is('img') ) {
3390
+ e.preventDefault();
3391
+ }
3392
+
3393
+ return;
3394
+ }
3395
+
3396
+ if ( !( $.fancybox.isMobile && ( isScrollable( self.$target ) || isScrollable( self.$target.parent() ) ) ) ) {
3397
+ e.preventDefault();
3398
+ }
3399
+
3400
+ self.canvasWidth = Math.round( current.$slide[0].clientWidth );
3401
+ self.canvasHeight = Math.round( current.$slide[0].clientHeight );
3402
+
3403
+ self.startTime = new Date().getTime();
3404
+ self.distanceX = self.distanceY = self.distance = 0;
3405
+
3406
+ self.isPanning = false;
3407
+ self.isSwiping = false;
3408
+ self.isZooming = false;
3409
+
3410
+ self.sliderStartPos = self.sliderLastPos || { top: 0, left: 0 };
3411
+ self.contentStartPos = $.fancybox.getTranslate( self.$content );
3412
+ self.contentLastPos = null;
3413
+
3414
+ if ( self.startPoints.length === 1 && !self.isZooming ) {
3415
+ self.canTap = !instance.isSliding;
3416
+
3417
+ if ( current.type === 'image' && ( self.contentStartPos.width > self.canvasWidth + 1 || self.contentStartPos.height > self.canvasHeight + 1 ) ) {
3418
+
3419
+ $.fancybox.stop( self.$content );
3420
+
3421
+ self.$content.css( 'transition-duration', '0ms' );
3422
+
3423
+ self.isPanning = true;
3424
+
3425
+ } else {
3426
+
3427
+ self.isSwiping = true;
3428
+ }
3429
+
3430
+ self.$container.addClass('fancybox-controls--isGrabbing');
3431
+ }
3432
+
3433
+ if ( self.startPoints.length === 2 && !instance.isAnimating && !current.hasError && current.type === 'image' && ( current.isLoaded || current.$ghost ) ) {
3434
+ self.isZooming = true;
3435
+
3436
+ self.isSwiping = false;
3437
+ self.isPanning = false;
3438
+
3439
+ $.fancybox.stop( self.$content );
3440
+
3441
+ self.$content.css( 'transition-duration', '0ms' );
3442
+
3443
+ self.centerPointStartX = ( ( self.startPoints[0].x + self.startPoints[1].x ) * 0.5 ) - $(window).scrollLeft();
3444
+ self.centerPointStartY = ( ( self.startPoints[0].y + self.startPoints[1].y ) * 0.5 ) - $(window).scrollTop();
3445
+
3446
+ self.percentageOfImageAtPinchPointX = ( self.centerPointStartX - self.contentStartPos.left ) / self.contentStartPos.width;
3447
+ self.percentageOfImageAtPinchPointY = ( self.centerPointStartY - self.contentStartPos.top ) / self.contentStartPos.height;
3448
+
3449
+ self.startDistanceBetweenFingers = distance( self.startPoints[0], self.startPoints[1] );
3450
+ }
3451
+
3452
+ };
3453
+
3454
+ Guestures.prototype.ontouchmove = function( e ) {
3455
+
3456
+ var self = this;
3457
+
3458
+ self.newPoints = pointers( e );
3459
+
3460
+ if ( $.fancybox.isMobile && ( isScrollable( self.$target ) || isScrollable( self.$target.parent() ) ) ) {
3461
+ e.stopPropagation();
3462
+
3463
+ self.canTap = false;
3464
+
3465
+ return;
3466
+ }
3467
+
3468
+ if ( !( self.instance.current.opts.touch || self.instance.canPan() ) || !self.newPoints || !self.newPoints.length ) {
3469
+ return;
3470
+ }
3471
+
3472
+ self.distanceX = distance( self.newPoints[0], self.startPoints[0], 'x' );
3473
+ self.distanceY = distance( self.newPoints[0], self.startPoints[0], 'y' );
3474
+
3475
+ self.distance = distance( self.newPoints[0], self.startPoints[0] );
3476
+
3477
+ // Skip false ontouchmove events (Chrome)
3478
+ if ( self.distance > 0 ) {
3479
+
3480
+ if ( !( self.$target.is( self.$stage ) || self.$stage.find( self.$target ).length ) ) {
3481
+ return;
3482
+ }
3483
+
3484
+ e.stopPropagation();
3485
+ e.preventDefault();
3486
+
3487
+ if ( self.isSwiping ) {
3488
+ self.onSwipe();
3489
+
3490
+ } else if ( self.isPanning ) {
3491
+ self.onPan();
3492
+
3493
+ } else if ( self.isZooming ) {
3494
+ self.onZoom();
3495
+ }
3496
+
3497
+ }
3498
+
3499
+ };
3500
+
3501
+ Guestures.prototype.onSwipe = function() {
3502
+
3503
+ var self = this;
3504
+
3505
+ var swiping = self.isSwiping;
3506
+ var left = self.sliderStartPos.left || 0;
3507
+ var angle;
3508
+
3509
+ if ( swiping === true ) {
3510
+
3511
+ if ( Math.abs( self.distance ) > 10 ) {
3512
+
3513
+ self.canTap = false;
3514
+
3515
+ if ( self.instance.group.length < 2 && self.instance.opts.touch.vertical ) {
3516
+ self.isSwiping = 'y';
3517
+
3518
+ } else if ( self.instance.isSliding || self.instance.opts.touch.vertical === false || ( self.instance.opts.touch.vertical === 'auto' && $( window ).width() > 800 ) ) {
3519
+ self.isSwiping = 'x';
3520
+
3521
+ } else {
3522
+ angle = Math.abs( Math.atan2( self.distanceY, self.distanceX ) * 180 / Math.PI );
3523
+
3524
+ self.isSwiping = ( angle > 45 && angle < 135 ) ? 'y' : 'x';
3525
+ }
3526
+
3527
+ self.instance.isSliding = self.isSwiping;
3528
+
3529
+ // Reset points to avoid jumping, because we dropped first swipes to calculate the angle
3530
+ self.startPoints = self.newPoints;
3531
+
3532
+ $.each(self.instance.slides, function( index, slide ) {
3533
+ $.fancybox.stop( slide.$slide );
3534
+
3535
+ slide.$slide.css( 'transition-duration', '0ms' );
3536
+
3537
+ slide.inTransition = false;
3538
+
3539
+ if ( slide.pos === self.instance.current.pos ) {
3540
+ self.sliderStartPos.left = $.fancybox.getTranslate( slide.$slide ).left;
3541
+ }
3542
+ });
3543
+
3544
+ //self.instance.current.isMoved = true;
3545
+
3546
+ // Stop slideshow
3547
+ if ( self.instance.SlideShow && self.instance.SlideShow.isActive ) {
3548
+ self.instance.SlideShow.stop();
3549
+ }
3550
+ }
3551
+
3552
+ } else {
3553
+
3554
+ if ( swiping == 'x' ) {
3555
+
3556
+ // Sticky edges
3557
+ if ( self.distanceX > 0 && ( self.instance.group.length < 2 || ( self.instance.current.index === 0 && !self.instance.current.opts.loop ) ) ) {
3558
+ left = left + Math.pow( self.distanceX, 0.8 );
3559
+
3560
+ } else if ( self.distanceX < 0 && ( self.instance.group.length < 2 || ( self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop ) ) ) {
3561
+ left = left - Math.pow( -self.distanceX, 0.8 );
3562
+
3563
+ } else {
3564
+ left = left + self.distanceX;
3565
+ }
3566
+
3567
+ }
3568
+
3569
+ self.sliderLastPos = {
3570
+ top : swiping == 'x' ? 0 : self.sliderStartPos.top + self.distanceY,
3571
+ left : left
3572
+ };
3573
+
3574
+ if ( self.requestId ) {
3575
+ cancelAFrame( self.requestId );
3576
+
3577
+ self.requestId = null;
3578
+ }
3579
+
3580
+ self.requestId = requestAFrame(function() {
3581
+
3582
+ if ( self.sliderLastPos ) {
3583
+ $.each(self.instance.slides, function( index, slide ) {
3584
+ var pos = slide.pos - self.instance.currPos;
3585
+
3586
+ $.fancybox.setTranslate( slide.$slide, {
3587
+ top : self.sliderLastPos.top,
3588
+ left : self.sliderLastPos.left + ( pos * self.canvasWidth ) + ( pos * slide.opts.gutter )
3589
+ });
3590
+ });
3591
+
3592
+ self.$container.addClass( 'fancybox-is-sliding' );
3593
+ }
3594
+
3595
+ });
3596
+
3597
+ }
3598
+
3599
+ };
3600
+
3601
+ Guestures.prototype.onPan = function() {
3602
+
3603
+ var self = this;
3604
+
3605
+ var newOffsetX, newOffsetY, newPos;
3606
+
3607
+ self.canTap = false;
3608
+
3609
+ if ( self.contentStartPos.width > self.canvasWidth ) {
3610
+ newOffsetX = self.contentStartPos.left + self.distanceX;
3611
+
3612
+ } else {
3613
+ newOffsetX = self.contentStartPos.left;
3614
+ }
3615
+
3616
+ newOffsetY = self.contentStartPos.top + self.distanceY;
3617
+
3618
+ newPos = self.limitMovement( newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height );
3619
+
3620
+ newPos.scaleX = self.contentStartPos.scaleX;
3621
+ newPos.scaleY = self.contentStartPos.scaleY;
3622
+
3623
+ self.contentLastPos = newPos;
3624
+
3625
+ if ( self.requestId ) {
3626
+ cancelAFrame( self.requestId );
3627
+
3628
+ self.requestId = null;
3629
+ }
3630
+
3631
+ self.requestId = requestAFrame(function() {
3632
+ $.fancybox.setTranslate( self.$content, self.contentLastPos );
3633
+ });
3634
+ };
3635
+
3636
+ // Make panning sticky to the edges
3637
+ Guestures.prototype.limitMovement = function( newOffsetX, newOffsetY, newWidth, newHeight ) {
3638
+
3639
+ var self = this;
3640
+
3641
+ var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY;
3642
+
3643
+ var canvasWidth = self.canvasWidth;
3644
+ var canvasHeight = self.canvasHeight;
3645
+
3646
+ var currentOffsetX = self.contentStartPos.left;
3647
+ var currentOffsetY = self.contentStartPos.top;
3648
+
3649
+ var distanceX = self.distanceX;
3650
+ var distanceY = self.distanceY;
3651
+
3652
+ // Slow down proportionally to traveled distance
3653
+
3654
+ minTranslateX = Math.max(0, canvasWidth * 0.5 - newWidth * 0.5 );
3655
+ minTranslateY = Math.max(0, canvasHeight * 0.5 - newHeight * 0.5 );
3656
+
3657
+ maxTranslateX = Math.min( canvasWidth - newWidth, canvasWidth * 0.5 - newWidth * 0.5 );
3658
+ maxTranslateY = Math.min( canvasHeight - newHeight, canvasHeight * 0.5 - newHeight * 0.5 );
3659
+
3660
+ if ( newWidth > canvasWidth ) {
3661
+
3662
+ // ->
3663
+ if ( distanceX > 0 && newOffsetX > minTranslateX ) {
3664
+ newOffsetX = minTranslateX - 1 + Math.pow( -minTranslateX + currentOffsetX + distanceX, 0.8 ) || 0;
3665
+ }
3666
+
3667
+ // <-
3668
+ if ( distanceX < 0 && newOffsetX < maxTranslateX ) {
3669
+ newOffsetX = maxTranslateX + 1 - Math.pow( maxTranslateX - currentOffsetX - distanceX, 0.8 ) || 0;
3670
+ }
3671
+
3672
+ }
3673
+
3674
+ if ( newHeight > canvasHeight ) {
3675
+
3676
+ // \/
3677
+ if ( distanceY > 0 && newOffsetY > minTranslateY ) {
3678
+ newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8 ) || 0;
3679
+ }
3680
+
3681
+ // /\
3682
+ if ( distanceY < 0 && newOffsetY < maxTranslateY ) {
3683
+ newOffsetY = maxTranslateY + 1 - Math.pow ( maxTranslateY - currentOffsetY - distanceY, 0.8 ) || 0;
3684
+ }
3685
+
3686
+ }
3687
+
3688
+ return {
3689
+ top : newOffsetY,
3690
+ left : newOffsetX
3691
+ };
3692
+
3693
+ };
3694
+
3695
+
3696
+ Guestures.prototype.limitPosition = function( newOffsetX, newOffsetY, newWidth, newHeight ) {
3697
+
3698
+ var self = this;
3699
+
3700
+ var canvasWidth = self.canvasWidth;
3701
+ var canvasHeight = self.canvasHeight;
3702
+
3703
+ if ( newWidth > canvasWidth ) {
3704
+ newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;
3705
+ newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX;
3706
+
3707
+ } else {
3708
+
3709
+ // Center horizontally
3710
+ newOffsetX = Math.max( 0, canvasWidth / 2 - newWidth / 2 );
3711
+
3712
+ }
3713
+
3714
+ if ( newHeight > canvasHeight ) {
3715
+ newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;
3716
+ newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY;
3717
+
3718
+ } else {
3719
+
3720
+ // Center vertically
3721
+ newOffsetY = Math.max( 0, canvasHeight / 2 - newHeight / 2 );
3722
+
3723
+ }
3724
+
3725
+ return {
3726
+ top : newOffsetY,
3727
+ left : newOffsetX
3728
+ };
3729
+
3730
+ };
3731
+
3732
+ Guestures.prototype.onZoom = function() {
3733
+
3734
+ var self = this;
3735
+
3736
+ // Calculate current distance between points to get pinch ratio and new width and height
3737
+
3738
+ var currentWidth = self.contentStartPos.width;
3739
+ var currentHeight = self.contentStartPos.height;
3740
+
3741
+ var currentOffsetX = self.contentStartPos.left;
3742
+ var currentOffsetY = self.contentStartPos.top;
3743
+
3744
+ var endDistanceBetweenFingers = distance( self.newPoints[0], self.newPoints[1] );
3745
+
3746
+ var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers;
3747
+
3748
+ var newWidth = Math.floor( currentWidth * pinchRatio );
3749
+ var newHeight = Math.floor( currentHeight * pinchRatio );
3750
+
3751
+ // This is the translation due to pinch-zooming
3752
+ var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;
3753
+ var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;
3754
+
3755
+ //Point between the two touches
3756
+
3757
+ var centerPointEndX = ((self.newPoints[0].x + self.newPoints[1].x) / 2) - $(window).scrollLeft();
3758
+ var centerPointEndY = ((self.newPoints[0].y + self.newPoints[1].y) / 2) - $(window).scrollTop();
3759
+
3760
+ // And this is the translation due to translation of the centerpoint
3761
+ // between the two fingers
3762
+
3763
+ var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;
3764
+ var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;
3765
+
3766
+ // The new offset is the old/current one plus the total translation
3767
+
3768
+ var newOffsetX = currentOffsetX + ( translateFromZoomingX + translateFromTranslatingX );
3769
+ var newOffsetY = currentOffsetY + ( translateFromZoomingY + translateFromTranslatingY );
3770
+
3771
+ var newPos = {
3772
+ top : newOffsetY,
3773
+ left : newOffsetX,
3774
+ scaleX : self.contentStartPos.scaleX * pinchRatio,
3775
+ scaleY : self.contentStartPos.scaleY * pinchRatio
3776
+ };
3777
+
3778
+ self.canTap = false;
3779
+
3780
+ self.newWidth = newWidth;
3781
+ self.newHeight = newHeight;
3782
+
3783
+ self.contentLastPos = newPos;
3784
+
3785
+ if ( self.requestId ) {
3786
+ cancelAFrame( self.requestId );
3787
+
3788
+ self.requestId = null;
3789
+ }
3790
+
3791
+ self.requestId = requestAFrame(function() {
3792
+ $.fancybox.setTranslate( self.$content, self.contentLastPos );
3793
+ });
3794
+
3795
+ };
3796
+
3797
+ Guestures.prototype.ontouchend = function( e ) {
3798
+
3799
+ var self = this;
3800
+ var dMs = Math.max( (new Date().getTime() ) - self.startTime, 1);
3801
+
3802
+ var swiping = self.isSwiping;
3803
+ var panning = self.isPanning;
3804
+ var zooming = self.isZooming;
3805
+
3806
+ self.endPoints = pointers( e );
3807
+
3808
+ self.$container.removeClass( 'fancybox-controls--isGrabbing' );
3809
+
3810
+ $(document).off( '.fb.touch' );
3811
+
3812
+ if ( self.requestId ) {
3813
+ cancelAFrame( self.requestId );
3814
+
3815
+ self.requestId = null;
3816
+ }
3817
+
3818
+ self.isSwiping = false;
3819
+ self.isPanning = false;
3820
+ self.isZooming = false;
3821
+
3822
+ if ( self.canTap ) {
3823
+ return self.onTap( e );
3824
+ }
3825
+
3826
+ self.speed = 366;
3827
+
3828
+ // Speed in px/ms
3829
+ self.velocityX = self.distanceX / dMs * 0.5;
3830
+ self.velocityY = self.distanceY / dMs * 0.5;
3831
+
3832
+ self.speedX = Math.max( self.speed * 0.5, Math.min( self.speed * 1.5, ( 1 / Math.abs( self.velocityX ) ) * self.speed ) );
3833
+
3834
+ if ( panning ) {
3835
+ self.endPanning();
3836
+
3837
+ } else if ( zooming ) {
3838
+ self.endZooming();
3839
+
3840
+ } else {
3841
+ self.endSwiping( swiping );
3842
+ }
3843
+
3844
+ return;
3845
+ };
3846
+
3847
+ Guestures.prototype.endSwiping = function( swiping ) {
3848
+
3849
+ var self = this;
3850
+ var ret = false;
3851
+
3852
+ self.instance.isSliding = false;
3853
+ self.sliderLastPos = null;
3854
+
3855
+ // Close if swiped vertically / navigate if horizontally
3856
+ if ( swiping == 'y' && Math.abs( self.distanceY ) > 50 ) {
3857
+
3858
+ // Continue vertical movement
3859
+ $.fancybox.animate( self.instance.current.$slide, {
3860
+ top : self.sliderStartPos.top + self.distanceY + ( self.velocityY * 150 ),
3861
+ opacity : 0
3862
+ }, 150 );
3863
+
3864
+ ret = self.instance.close( true, 300 );
3865
+
3866
+ } else if ( swiping == 'x' && self.distanceX > 50 && self.instance.group.length > 1 ) {
3867
+ ret = self.instance.previous( self.speedX );
3868
+
3869
+ } else if ( swiping == 'x' && self.distanceX < -50 && self.instance.group.length > 1 ) {
3870
+ ret = self.instance.next( self.speedX );
3871
+ }
3872
+
3873
+ if ( ret === false && ( swiping == 'x' || swiping == 'y' ) ) {
3874
+ self.instance.jumpTo( self.instance.current.index, 150 );
3875
+ }
3876
+
3877
+ self.$container.removeClass( 'fancybox-is-sliding' );
3878
+
3879
+ };
3880
+
3881
+ // Limit panning from edges
3882
+ // ========================
3883
+
3884
+ Guestures.prototype.endPanning = function() {
3885
+
3886
+ var self = this;
3887
+ var newOffsetX, newOffsetY, newPos;
3888
+
3889
+ if ( !self.contentLastPos ) {
3890
+ return;
3891
+ }
3892
+
3893
+ if ( self.instance.current.opts.touch.momentum === false ) {
3894
+ newOffsetX = self.contentLastPos.left;
3895
+ newOffsetY = self.contentLastPos.top;
3896
+
3897
+ } else {
3898
+
3899
+ // Continue movement
3900
+ newOffsetX = self.contentLastPos.left + ( self.velocityX * self.speed );
3901
+ newOffsetY = self.contentLastPos.top + ( self.velocityY * self.speed );
3902
+ }
3903
+
3904
+ newPos = self.limitPosition( newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height );
3905
+
3906
+ newPos.width = self.contentStartPos.width;
3907
+ newPos.height = self.contentStartPos.height;
3908
+
3909
+ $.fancybox.animate( self.$content, newPos, 330 );
3910
+ };
3911
+
3912
+
3913
+ Guestures.prototype.endZooming = function() {
3914
+
3915
+ var self = this;
3916
+
3917
+ var current = self.instance.current;
3918
+
3919
+ var newOffsetX, newOffsetY, newPos, reset;
3920
+
3921
+ var newWidth = self.newWidth;
3922
+ var newHeight = self.newHeight;
3923
+
3924
+ if ( !self.contentLastPos ) {
3925
+ return;
3926
+ }
3927
+
3928
+ newOffsetX = self.contentLastPos.left;
3929
+ newOffsetY = self.contentLastPos.top;
3930
+
3931
+ reset = {
3932
+ top : newOffsetY,
3933
+ left : newOffsetX,
3934
+ width : newWidth,
3935
+ height : newHeight,
3936
+ scaleX : 1,
3937
+ scaleY : 1
3938
+ };
3939
+
3940
+ // Reset scalex/scaleY values; this helps for perfomance and does not break animation
3941
+ $.fancybox.setTranslate( self.$content, reset );
3942
+
3943
+ if ( newWidth < self.canvasWidth && newHeight < self.canvasHeight ) {
3944
+ self.instance.scaleToFit( 150 );
3945
+
3946
+ } else if ( newWidth > current.width || newHeight > current.height ) {
3947
+ self.instance.scaleToActual( self.centerPointStartX, self.centerPointStartY, 150 );
3948
+
3949
+ } else {
3950
+
3951
+ newPos = self.limitPosition( newOffsetX, newOffsetY, newWidth, newHeight );
3952
+
3953
+ // Switch from scale() to width/height or animation will not work correctly
3954
+ $.fancybox.setTranslate( self.content, $.fancybox.getTranslate( self.$content ) );
3955
+
3956
+ $.fancybox.animate( self.$content, newPos, 150 );
3957
+ }
3958
+
3959
+ };
3960
+
3961
+ Guestures.prototype.onTap = function(e) {
3962
+ var self = this;
3963
+ var $target = $( e.target );
3964
+
3965
+ var instance = self.instance;
3966
+ var current = instance.current;
3967
+
3968
+ var endPoints = ( e && pointers( e ) ) || self.startPoints;
3969
+
3970
+ var tapX = endPoints[0] ? endPoints[0].x - self.$stage.offset().left : 0;
3971
+ var tapY = endPoints[0] ? endPoints[0].y - self.$stage.offset().top : 0;
3972
+
3973
+ var where;
3974
+
3975
+ var process = function ( prefix ) {
3976
+
3977
+ var action = current.opts[ prefix ];
3978
+
3979
+ if ( $.isFunction( action ) ) {
3980
+ action = action.apply( instance, [ current, e ] );
3981
+ }
3982
+
3983
+ if ( !action) {
3984
+ return;
3985
+ }
3986
+
3987
+ switch ( action ) {
3988
+
3989
+ case "close" :
3990
+
3991
+ instance.close( self.startEvent );
3992
+
3993
+ break;
3994
+
3995
+ case "toggleControls" :
3996
+
3997
+ instance.toggleControls( true );
3998
+
3999
+ break;
4000
+
4001
+ case "next" :
4002
+
4003
+ instance.next();
4004
+
4005
+ break;
4006
+
4007
+ case "nextOrClose" :
4008
+
4009
+ if ( instance.group.length > 1 ) {
4010
+ instance.next();
4011
+
4012
+ } else {
4013
+ instance.close( self.startEvent );
4014
+ }
4015
+
4016
+ break;
4017
+
4018
+ case "zoom" :
4019
+
4020
+ if ( current.type == 'image' && ( current.isLoaded || current.$ghost ) ) {
4021
+
4022
+ if ( instance.canPan() ) {
4023
+ instance.scaleToFit();
4024
+
4025
+ } else if ( instance.isScaledDown() ) {
4026
+ instance.scaleToActual( tapX, tapY );
4027
+
4028
+ } else if ( instance.group.length < 2 ) {
4029
+ instance.close( self.startEvent );
4030
+ }
4031
+ }
4032
+
4033
+ break;
4034
+ }
4035
+
4036
+ };
4037
+
4038
+ // Ignore right click
4039
+ if ( e.originalEvent && e.originalEvent.button == 2 ) {
4040
+ return;
4041
+ }
4042
+
4043
+ // Skip if current slide is not in the center
4044
+ if ( instance.isSliding ) {
4045
+ return;
4046
+ }
4047
+
4048
+ // Skip if clicked on the scrollbar
4049
+ if ( tapX > $target[0].clientWidth + $target.offset().left ) {
4050
+ return;
4051
+ }
4052
+
4053
+ // Check where is clicked
4054
+ if ( $target.is( '.fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container' ) ) {
4055
+ where = 'Outside';
4056
+
4057
+ } else if ( $target.is( '.fancybox-slide' ) ) {
4058
+ where = 'Slide';
4059
+
4060
+ } else if ( instance.current.$content && instance.current.$content.has( e.target ).length ) {
4061
+ where = 'Content';
4062
+
4063
+ } else {
4064
+ return;
4065
+ }
4066
+
4067
+ // Check if this is a double tap
4068
+ if ( self.tapped ) {
4069
+
4070
+ // Stop previously created single tap
4071
+ clearTimeout( self.tapped );
4072
+ self.tapped = null;
4073
+
4074
+ // Skip if distance between taps is too big
4075
+ if ( Math.abs( tapX - self.tapX ) > 50 || Math.abs( tapY - self.tapY ) > 50 || instance.isSliding ) {
4076
+ return this;
4077
+ }
4078
+
4079
+ // OK, now we assume that this is a double-tap
4080
+ process( 'dblclick' + where );
4081
+
4082
+ } else {
4083
+
4084
+ // Single tap will be processed if user has not clicked second time within 300ms
4085
+ // or there is no need to wait for double-tap
4086
+ self.tapX = tapX;
4087
+ self.tapY = tapY;
4088
+
4089
+ if ( current.opts[ 'dblclick' + where ] && current.opts[ 'dblclick' + where ] !== current.opts[ 'click' + where ] ) {
4090
+ self.tapped = setTimeout(function() {
4091
+ self.tapped = null;
4092
+
4093
+ process( 'click' + where );
4094
+
4095
+ }, 300);
4096
+
4097
+ } else {
4098
+ process( 'click' + where );
4099
+ }
4100
+
4101
+ }
4102
+
4103
+ return this;
4104
+ };
4105
+
4106
+ $(document).on('onActivate.fb', function (e, instance) {
4107
+ if ( instance && !instance.Guestures ) {
4108
+ instance.Guestures = new Guestures( instance );
4109
+ }
4110
+ });
4111
+
4112
+ $(document).on('beforeClose.fb', function (e, instance) {
4113
+ if ( instance && instance.Guestures ) {
4114
+ instance.Guestures.destroy();
4115
+ }
4116
+ });
4117
+
4118
+
4119
+ }(window, document, window.jQuery));
4120
+
4121
+ // ==========================================================================
4122
+ //
4123
+ // SlideShow
4124
+ // Enables slideshow functionality
4125
+ //
4126
+ // Example of usage:
4127
+ // $.fancybox.getInstance().SlideShow.start()
4128
+ //
4129
+ // ==========================================================================
4130
+ ;(function (document, $) {
4131
+ 'use strict';
4132
+
4133
+ var SlideShow = function( instance ) {
4134
+ this.instance = instance;
4135
+ this.init();
4136
+ };
4137
+
4138
+ $.extend( SlideShow.prototype, {
4139
+ timer : null,
4140
+ isActive : false,
4141
+ $button : null,
4142
+ speed : 3000,
4143
+
4144
+ init : function() {
4145
+ var self = this;
4146
+
4147
+ self.$button = self.instance.$refs.toolbar.find('[data-fancybox-play]').on('click', function() {
4148
+ self.toggle();
4149
+ });
4150
+
4151
+ if ( self.instance.group.length < 2 || !self.instance.group[ self.instance.currIndex ].opts.slideShow ) {
4152
+ self.$button.hide();
4153
+ }
4154
+ },
4155
+
4156
+ set : function() {
4157
+ var self = this;
4158
+
4159
+ // Check if reached last element
4160
+ if ( self.instance && self.instance.current && (self.instance.current.opts.loop || self.instance.currIndex < self.instance.group.length - 1 )) {
4161
+ self.timer = setTimeout(function() {
4162
+ self.instance.next();
4163
+
4164
+ }, self.instance.current.opts.slideShow.speed || self.speed);
4165
+
4166
+ } else {
4167
+ self.stop();
4168
+ self.instance.idleSecondsCounter = 0;
4169
+ self.instance.showControls();
4170
+ }
4171
+
4172
+ },
4173
+
4174
+ clear : function() {
4175
+ var self = this;
4176
+
4177
+ clearTimeout( self.timer );
4178
+
4179
+ self.timer = null;
4180
+ },
4181
+
4182
+ start : function() {
4183
+ var self = this;
4184
+ var current = self.instance.current;
4185
+
4186
+ if ( self.instance && current && ( current.opts.loop || current.index < self.instance.group.length - 1 )) {
4187
+
4188
+ self.isActive = true;
4189
+
4190
+ self.$button
4191
+ .attr( 'title', current.opts.i18n[ current.opts.lang ].PLAY_STOP )
4192
+ .addClass( 'fancybox-button--pause' );
4193
+
4194
+ if ( current.isComplete ) {
4195
+ self.set();
4196
+ }
4197
+ }
4198
+ },
4199
+
4200
+ stop : function() {
4201
+ var self = this;
4202
+ var current = self.instance.current;
4203
+
4204
+ self.clear();
4205
+
4206
+ self.$button
4207
+ .attr( 'title', current.opts.i18n[ current.opts.lang ].PLAY_START )
4208
+ .removeClass( 'fancybox-button--pause' );
4209
+
4210
+ self.isActive = false;
4211
+ },
4212
+
4213
+ toggle : function() {
4214
+ var self = this;
4215
+
4216
+ if ( self.isActive ) {
4217
+ self.stop();
4218
+
4219
+ } else {
4220
+ self.start();
4221
+ }
4222
+ }
4223
+
4224
+ });
4225
+
4226
+ $(document).on({
4227
+ 'onInit.fb' : function(e, instance) {
4228
+ if ( instance && !instance.SlideShow ) {
4229
+ instance.SlideShow = new SlideShow( instance );
4230
+ }
4231
+ },
4232
+
4233
+ 'beforeShow.fb' : function(e, instance, current, firstRun) {
4234
+ var SlideShow = instance && instance.SlideShow;
4235
+
4236
+ if ( firstRun ) {
4237
+
4238
+ if ( SlideShow && current.opts.slideShow.autoStart ) {
4239
+ SlideShow.start();
4240
+ }
4241
+
4242
+ } else if ( SlideShow && SlideShow.isActive ) {
4243
+ SlideShow.clear();
4244
+ }
4245
+ },
4246
+
4247
+ 'afterShow.fb' : function(e, instance, current) {
4248
+ var SlideShow = instance && instance.SlideShow;
4249
+
4250
+ if ( SlideShow && SlideShow.isActive ) {
4251
+ SlideShow.set();
4252
+ }
4253
+ },
4254
+
4255
+ 'afterKeydown.fb' : function(e, instance, current, keypress, keycode) {
4256
+ var SlideShow = instance && instance.SlideShow;
4257
+
4258
+ // "P" or Spacebar
4259
+ if ( SlideShow && current.opts.slideShow && ( keycode === 80 || keycode === 32 ) && !$(document.activeElement).is( 'button,a,input' ) ) {
4260
+ keypress.preventDefault();
4261
+
4262
+ SlideShow.toggle();
4263
+ }
4264
+ },
4265
+
4266
+ 'beforeClose.fb onDeactivate.fb' : function(e, instance) {
4267
+ var SlideShow = instance && instance.SlideShow;
4268
+
4269
+ if ( SlideShow ) {
4270
+ SlideShow.stop();
4271
+ }
4272
+ }
4273
+ });
4274
+
4275
+ // Page Visibility API to pause slideshow when window is not active
4276
+ $(document).on("visibilitychange", function() {
4277
+ var instance = $.fancybox.getInstance();
4278
+ var SlideShow = instance && instance.SlideShow;
4279
+
4280
+ if ( SlideShow && SlideShow.isActive ) {
4281
+ if ( document.hidden ) {
4282
+ SlideShow.clear();
4283
+
4284
+ } else {
4285
+ SlideShow.set();
4286
+ }
4287
+ }
4288
+ });
4289
+
4290
+ }(document, window.jQuery));
4291
+
4292
+ // ==========================================================================
4293
+ //
4294
+ // FullScreen
4295
+ // Adds fullscreen functionality
4296
+ //
4297
+ // ==========================================================================
4298
+ ;(function (document, $) {
4299
+ 'use strict';
4300
+
4301
+ // Collection of methods supported by user browser
4302
+ var fn = (function () {
4303
+
4304
+ var fnMap = [
4305
+ [
4306
+ 'requestFullscreen',
4307
+ 'exitFullscreen',
4308
+ 'fullscreenElement',
4309
+ 'fullscreenEnabled',
4310
+ 'fullscreenchange',
4311
+ 'fullscreenerror'
4312
+ ],
4313
+ // new WebKit
4314
+ [
4315
+ 'webkitRequestFullscreen',
4316
+ 'webkitExitFullscreen',
4317
+ 'webkitFullscreenElement',
4318
+ 'webkitFullscreenEnabled',
4319
+ 'webkitfullscreenchange',
4320
+ 'webkitfullscreenerror'
4321
+
4322
+ ],
4323
+ // old WebKit (Safari 5.1)
4324
+ [
4325
+ 'webkitRequestFullScreen',
4326
+ 'webkitCancelFullScreen',
4327
+ 'webkitCurrentFullScreenElement',
4328
+ 'webkitCancelFullScreen',
4329
+ 'webkitfullscreenchange',
4330
+ 'webkitfullscreenerror'
4331
+
4332
+ ],
4333
+ [
4334
+ 'mozRequestFullScreen',
4335
+ 'mozCancelFullScreen',
4336
+ 'mozFullScreenElement',
4337
+ 'mozFullScreenEnabled',
4338
+ 'mozfullscreenchange',
4339
+ 'mozfullscreenerror'
4340
+ ],
4341
+ [
4342
+ 'msRequestFullscreen',
4343
+ 'msExitFullscreen',
4344
+ 'msFullscreenElement',
4345
+ 'msFullscreenEnabled',
4346
+ 'MSFullscreenChange',
4347
+ 'MSFullscreenError'
4348
+ ]
4349
+ ];
4350
+
4351
+ var val;
4352
+ var ret = {};
4353
+ var i, j;
4354
+
4355
+ for ( i = 0; i < fnMap.length; i++ ) {
4356
+ val = fnMap[ i ];
4357
+
4358
+ if ( val && val[ 1 ] in document ) {
4359
+ for ( j = 0; j < val.length; j++ ) {
4360
+ ret[ fnMap[ 0 ][ j ] ] = val[ j ];
4361
+ }
4362
+
4363
+ return ret;
4364
+ }
4365
+ }
4366
+
4367
+ return false;
4368
+ })();
4369
+
4370
+ // If browser does not have Full Screen API, then simply unset default button template and stop
4371
+ if ( !fn ) {
4372
+ $.fancybox.defaults.btnTpl.fullScreen = false;
4373
+
4374
+ return;
4375
+ }
4376
+
4377
+ var FullScreen = {
4378
+ request : function ( elem ) {
4379
+
4380
+ elem = elem || document.documentElement;
4381
+
4382
+ elem[ fn.requestFullscreen ]( elem.ALLOW_KEYBOARD_INPUT );
4383
+
4384
+ },
4385
+ exit : function () {
4386
+
4387
+ document[ fn.exitFullscreen ]();
4388
+
4389
+ },
4390
+ toggle : function ( elem ) {
4391
+
4392
+ elem = elem || document.documentElement;
4393
+
4394
+ if ( this.isFullscreen() ) {
4395
+ this.exit();
4396
+
4397
+ } else {
4398
+ this.request( elem );
4399
+ }
4400
+
4401
+ },
4402
+ isFullscreen : function() {
4403
+
4404
+ return Boolean( document[ fn.fullscreenElement ] );
4405
+
4406
+ },
4407
+ enabled : function() {
4408
+
4409
+ return Boolean( document[ fn.fullscreenEnabled ] );
4410
+
4411
+ }
4412
+ };
4413
+
4414
+ $(document).on({
4415
+ 'onInit.fb' : function(e, instance) {
4416
+ var $container;
4417
+
4418
+ var $button = instance.$refs.toolbar.find('[data-fancybox-fullscreen]');
4419
+
4420
+ if ( instance && !instance.FullScreen && instance.group[ instance.currIndex ].opts.fullScreen ) {
4421
+ $container = instance.$refs.container;
4422
+
4423
+ $container.on('click.fb-fullscreen', '[data-fancybox-fullscreen]', function(e) {
4424
+
4425
+ e.stopPropagation();
4426
+ e.preventDefault();
4427
+
4428
+ FullScreen.toggle( $container[ 0 ] );
4429
+
4430
+ });
4431
+
4432
+ if ( instance.opts.fullScreen && instance.opts.fullScreen.autoStart === true ) {
4433
+ FullScreen.request( $container[ 0 ] );
4434
+ }
4435
+
4436
+ // Expose API
4437
+ instance.FullScreen = FullScreen;
4438
+
4439
+ } else {
4440
+ $button.hide();
4441
+ }
4442
+
4443
+ },
4444
+
4445
+ 'afterKeydown.fb' : function(e, instance, current, keypress, keycode) {
4446
+
4447
+ // "P" or Spacebar
4448
+ if ( instance && instance.FullScreen && keycode === 70 ) {
4449
+ keypress.preventDefault();
4450
+
4451
+ instance.FullScreen.toggle( instance.$refs.container[ 0 ] );
4452
+ }
4453
+
4454
+ },
4455
+
4456
+ 'beforeClose.fb' : function( instance ) {
4457
+ if ( instance && instance.FullScreen ) {
4458
+ FullScreen.exit();
4459
+ }
4460
+ }
4461
+ });
4462
+
4463
+ $(document).on(fn.fullscreenchange, function() {
4464
+ var instance = $.fancybox.getInstance();
4465
+
4466
+ // If image is zooming, then force to stop and reposition properly
4467
+ if ( instance.current && instance.current.type === 'image' && instance.isAnimating ) {
4468
+ instance.current.$content.css( 'transition', 'none' );
4469
+
4470
+ instance.isAnimating = false;
4471
+
4472
+ instance.update( true, true, 0 );
4473
+ }
4474
+
4475
+ });
4476
+
4477
+ }(document, window.jQuery));
4478
+
4479
+ // ==========================================================================
4480
+ //
4481
+ // Thumbs
4482
+ // Displays thumbnails in a grid
4483
+ //
4484
+ // ==========================================================================
4485
+ ;(function (document, $) {
4486
+ 'use strict';
4487
+
4488
+ var FancyThumbs = function( instance ) {
4489
+ this.instance = instance;
4490
+ this.init();
4491
+ };
4492
+
4493
+ $.extend( FancyThumbs.prototype, {
4494
+
4495
+ $button : null,
4496
+ $grid : null,
4497
+ $list : null,
4498
+ isVisible : false,
4499
+
4500
+ init : function() {
4501
+ var self = this;
4502
+
4503
+ var first = self.instance.group[0],
4504
+ second = self.instance.group[1];
4505
+
4506
+ self.$button = self.instance.$refs.toolbar.find( '[data-fancybox-thumbs]' );
4507
+
4508
+ if ( self.instance.group.length > 1 && self.instance.group[ self.instance.currIndex ].opts.thumbs && (
4509
+ ( first.type == 'image' || first.opts.thumb || first.opts.$thumb ) &&
4510
+ ( second.type == 'image' || second.opts.thumb || second.opts.$thumb )
4511
+ )) {
4512
+
4513
+ self.$button.on('click', function() {
4514
+ self.toggle();
4515
+ });
4516
+
4517
+ self.isActive = true;
4518
+
4519
+ } else {
4520
+ self.$button.hide();
4521
+
4522
+ self.isActive = false;
4523
+ }
4524
+
4525
+ },
4526
+
4527
+ create : function() {
4528
+ var instance = this.instance,
4529
+ list,
4530
+ src;
4531
+
4532
+ this.$grid = $('<div class="fancybox-thumbs"></div>').appendTo( instance.$refs.container );
4533
+
4534
+ list = '<ul>';
4535
+
4536
+ $.each(instance.group, function( i, item ) {
4537
+
4538
+ src = item.opts.thumb || ( item.opts.$thumb ? item.opts.$thumb.attr('src') : null );
4539
+
4540
+ if ( !src && item.type === 'image' ) {
4541
+ src = item.src;
4542
+ }
4543
+
4544
+ if ( src && src.length ) {
4545
+ list += '<li data-index="' + i + '" tabindex="0" class="fancybox-thumbs-loading"><img data-src="' + src + '" /></li>';
4546
+ }
4547
+
4548
+ });
4549
+
4550
+ list += '</ul>';
4551
+
4552
+ this.$list = $( list ).appendTo( this.$grid ).on('click', 'li', function() {
4553
+ instance.jumpTo( $(this).data('index') );
4554
+ });
4555
+
4556
+ this.$list.find('img').hide().one('load', function() {
4557
+
4558
+ var $parent = $(this).parent().removeClass('fancybox-thumbs-loading'),
4559
+ thumbWidth = $parent.outerWidth(),
4560
+ thumbHeight = $parent.outerHeight(),
4561
+ width,
4562
+ height,
4563
+ widthRatio,
4564
+ heightRatio;
4565
+
4566
+ width = this.naturalWidth || this.width;
4567
+ height = this.naturalHeight || this.height;
4568
+
4569
+ //Calculate thumbnail width/height and center it
4570
+
4571
+ widthRatio = width / thumbWidth;
4572
+ heightRatio = height / thumbHeight;
4573
+
4574
+ if (widthRatio >= 1 && heightRatio >= 1) {
4575
+ if (widthRatio > heightRatio) {
4576
+ width = width / heightRatio;
4577
+ height = thumbHeight;
4578
+
4579
+ } else {
4580
+ width = thumbWidth;
4581
+ height = height / widthRatio;
4582
+ }
4583
+ }
4584
+
4585
+ $(this).css({
4586
+ width : Math.floor(width),
4587
+ height : Math.floor(height),
4588
+ 'margin-top' : Math.min( 0, Math.floor(thumbHeight * 0.3 - height * 0.3 ) ),
4589
+ 'margin-left' : Math.min( 0, Math.floor(thumbWidth * 0.5 - width * 0.5 ) )
4590
+ }).show();
4591
+
4592
+ })
4593
+ .each(function() {
4594
+ this.src = $( this ).data( 'src' );
4595
+ });
4596
+
4597
+ },
4598
+
4599
+ focus : function() {
4600
+
4601
+ if ( this.instance.current ) {
4602
+ this.$list
4603
+ .children()
4604
+ .removeClass('fancybox-thumbs-active')
4605
+ .filter('[data-index="' + this.instance.current.index + '"]')
4606
+ .addClass('fancybox-thumbs-active')
4607
+ .focus();
4608
+ }
4609
+
4610
+ },
4611
+
4612
+ close : function() {
4613
+ this.$grid.hide();
4614
+ },
4615
+
4616
+ update : function() {
4617
+
4618
+ this.instance.$refs.container.toggleClass( 'fancybox-show-thumbs', this.isVisible );
4619
+
4620
+ if ( this.isVisible ) {
4621
+
4622
+ if ( !this.$grid ) {
4623
+ this.create();
4624
+ }
4625
+
4626
+ this.instance.trigger( 'onThumbsShow' );
4627
+
4628
+ this.focus();
4629
+
4630
+ } else if ( this.$grid ) {
4631
+ this.instance.trigger( 'onThumbsHide' );
4632
+ }
4633
+
4634
+ // Update content position
4635
+ this.instance.update();
4636
+
4637
+ },
4638
+
4639
+ hide : function() {
4640
+ this.isVisible = false;
4641
+ this.update();
4642
+ },
4643
+
4644
+ show : function() {
4645
+ this.isVisible = true;
4646
+ this.update();
4647
+ },
4648
+
4649
+ toggle : function() {
4650
+ this.isVisible = !this.isVisible;
4651
+ this.update();
4652
+ }
4653
+
4654
+ });
4655
+
4656
+ $(document).on({
4657
+
4658
+ 'onInit.fb' : function(e, instance) {
4659
+ if ( instance && !instance.Thumbs ) {
4660
+ instance.Thumbs = new FancyThumbs( instance );
4661
+ }
4662
+ },
4663
+
4664
+ 'beforeShow.fb' : function(e, instance, item, firstRun) {
4665
+ var Thumbs = instance && instance.Thumbs;
4666
+
4667
+ if ( !Thumbs || !Thumbs.isActive ) {
4668
+ return;
4669
+ }
4670
+
4671
+ if ( item.modal ) {
4672
+ Thumbs.$button.hide();
4673
+
4674
+ Thumbs.hide();
4675
+
4676
+ return;
4677
+ }
4678
+
4679
+ if ( firstRun && instance.opts.thumbs.autoStart === true ) {
4680
+ Thumbs.show();
4681
+ }
4682
+
4683
+ if ( Thumbs.isVisible ) {
4684
+ Thumbs.focus();
4685
+ }
4686
+ },
4687
+
4688
+ 'afterKeydown.fb' : function(e, instance, current, keypress, keycode) {
4689
+ var Thumbs = instance && instance.Thumbs;
4690
+
4691
+ // "G"
4692
+ if ( Thumbs && Thumbs.isActive && keycode === 71 ) {
4693
+ keypress.preventDefault();
4694
+
4695
+ Thumbs.toggle();
4696
+ }
4697
+ },
4698
+
4699
+ 'beforeClose.fb' : function( e, instance ) {
4700
+ var Thumbs = instance && instance.Thumbs;
4701
+
4702
+ if ( Thumbs && Thumbs.isVisible && instance.opts.thumbs.hideOnClose !== false ) {
4703
+ Thumbs.close();
4704
+ }
4705
+ }
4706
+
4707
+ });
4708
+
4709
+ }(document, window.jQuery));
4710
+
4711
+ // ==========================================================================
4712
+ //
4713
+ // Hash
4714
+ // Enables linking to each modal
4715
+ //
4716
+ // ==========================================================================
4717
+ ;(function (document, window, $) {
4718
+ 'use strict';
4719
+
4720
+ // Simple $.escapeSelector polyfill (for jQuery prior v3)
4721
+ if ( !$.escapeSelector ) {
4722
+ $.escapeSelector = function( sel ) {
4723
+ var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
4724
+ var fcssescape = function( ch, asCodePoint ) {
4725
+ if ( asCodePoint ) {
4726
+ // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
4727
+ if ( ch === "\0" ) {
4728
+ return "\uFFFD";
4729
+ }
4730
+
4731
+ // Control characters and (dependent upon position) numbers get escaped as code points
4732
+ return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
4733
+ }
4734
+
4735
+ // Other potentially-special ASCII characters get backslash-escaped
4736
+ return "\\" + ch;
4737
+ };
4738
+
4739
+ return ( sel + "" ).replace( rcssescape, fcssescape );
4740
+ };
4741
+ }
4742
+
4743
+ // Create new history entry only once
4744
+ var shouldCreateHistory = true;
4745
+
4746
+ // Variable containing last hash value set by fancyBox
4747
+ // It will be used to determine if fancyBox needs to close after hash change is detected
4748
+ var currentHash = null;
4749
+
4750
+ // Throttling the history change
4751
+ var timerID = null;
4752
+
4753
+ // Get info about gallery name and current index from url
4754
+ function parseUrl() {
4755
+ var hash = window.location.hash.substr( 1 );
4756
+ var rez = hash.split( '-' );
4757
+ var index = rez.length > 1 && /^\+?\d+$/.test( rez[ rez.length - 1 ] ) ? parseInt( rez.pop( -1 ), 10 ) || 1 : 1;
4758
+ var gallery = rez.join( '-' );
4759
+
4760
+ // Index is starting from 1
4761
+ if ( index < 1 ) {
4762
+ index = 1;
4763
+ }
4764
+
4765
+ return {
4766
+ hash : hash,
4767
+ index : index,
4768
+ gallery : gallery
4769
+ };
4770
+ }
4771
+
4772
+ // Trigger click evnt on links to open new fancyBox instance
4773
+ function triggerFromUrl( url ) {
4774
+ var $el;
4775
+
4776
+ if ( url.gallery !== '' ) {
4777
+
4778
+ // If we can find element matching 'data-fancybox' atribute, then trigger click event for that ..
4779
+ $el = $( "[data-fancybox='" + $.escapeSelector( url.gallery ) + "']" ).eq( url.index - 1 );
4780
+
4781
+ if ( !$el.length ) {
4782
+ // .. if not, try finding element by ID
4783
+ $el = $( "#" + $.escapeSelector( url.gallery ) + "" );
4784
+ }
4785
+
4786
+ if ( $el.length ) {
4787
+ shouldCreateHistory = false;
4788
+
4789
+ $el.trigger( 'click' );
4790
+ }
4791
+
4792
+ }
4793
+ }
4794
+
4795
+ // Get gallery name from current instance
4796
+ function getGallery( instance ) {
4797
+ var opts;
4798
+
4799
+ if ( !instance ) {
4800
+ return false;
4801
+ }
4802
+
4803
+ opts = instance.current ? instance.current.opts : instance.opts;
4804
+
4805
+ return opts.$orig ? opts.$orig.data( 'fancybox' ) : ( opts.hash || '' );
4806
+ }
4807
+
4808
+ // Star when DOM becomes ready
4809
+ $(function() {
4810
+
4811
+ // Small delay is used to allow other scripts to process "dom ready" event
4812
+ setTimeout(function() {
4813
+
4814
+ // Check if this module is not disabled
4815
+ if ( $.fancybox.defaults.hash === false ) {
4816
+ return;
4817
+ }
4818
+
4819
+ // Update hash when opening/closing fancyBox
4820
+ $(document).on({
4821
+ 'onInit.fb' : function( e, instance ) {
4822
+ var url, gallery;
4823
+
4824
+ if ( instance.group[ instance.currIndex ].opts.hash === false ) {
4825
+ return;
4826
+ }
4827
+
4828
+ url = parseUrl();
4829
+ gallery = getGallery( instance );
4830
+
4831
+ // Make sure gallery start index matches index from hash
4832
+ if ( gallery && url.gallery && gallery == url.gallery ) {
4833
+ instance.currIndex = url.index - 1;
4834
+ }
4835
+
4836
+ },
4837
+
4838
+ 'beforeShow.fb' : function( e, instance, current ) {
4839
+ var gallery;
4840
+
4841
+ if ( current.opts.hash === false ) {
4842
+ return;
4843
+ }
4844
+
4845
+ gallery = getGallery( instance );
4846
+
4847
+ // Update window hash
4848
+ if ( gallery && gallery !== '' ) {
4849
+
4850
+ if ( window.location.hash.indexOf( gallery ) < 0 ) {
4851
+ instance.opts.origHash = window.location.hash;
4852
+ }
4853
+
4854
+ currentHash = gallery + ( instance.group.length > 1 ? '-' + ( current.index + 1 ) : '' );
4855
+
4856
+ if ( 'replaceState' in window.history ) {
4857
+ if ( timerID ) {
4858
+ clearTimeout( timerID );
4859
+ }
4860
+
4861
+ timerID = setTimeout(function() {
4862
+ window.history[ shouldCreateHistory ? 'pushState' : 'replaceState' ]( {} , document.title, window.location.pathname + window.location.search + '#' + currentHash );
4863
+
4864
+ timerID = null;
4865
+
4866
+ shouldCreateHistory = false;
4867
+
4868
+ }, 300);
4869
+
4870
+ } else {
4871
+ window.location.hash = currentHash;
4872
+ }
4873
+
4874
+ }
4875
+
4876
+ },
4877
+
4878
+ 'beforeClose.fb' : function( e, instance, current ) {
4879
+ var gallery, origHash;
4880
+
4881
+ if ( timerID ) {
4882
+ clearTimeout( timerID );
4883
+ }
4884
+
4885
+ if ( current.opts.hash === false ) {
4886
+ return;
4887
+ }
4888
+
4889
+ gallery = getGallery( instance );
4890
+ origHash = instance && instance.opts.origHash ? instance.opts.origHash : '';
4891
+
4892
+ // Remove hash from location bar
4893
+ if ( gallery && gallery !== '' ) {
4894
+
4895
+ if ( 'replaceState' in history ) {
4896
+ window.history.replaceState( {} , document.title, window.location.pathname + window.location.search + origHash );
4897
+
4898
+ } else {
4899
+ window.location.hash = origHash;
4900
+
4901
+ // Keep original scroll position
4902
+ $( window ).scrollTop( instance.scrollTop ).scrollLeft( instance.scrollLeft );
4903
+ }
4904
+ }
4905
+
4906
+ currentHash = null;
4907
+ }
4908
+ });
4909
+
4910
+ // Check if need to close after url has changed
4911
+ $(window).on('hashchange.fb', function() {
4912
+ var url = parseUrl();
4913
+
4914
+ if ( $.fancybox.getInstance() ) {
4915
+ if ( currentHash && currentHash !== url.gallery + '-' + url.index && !( url.index === 1 && currentHash == url.gallery ) ) {
4916
+ currentHash = null;
4917
+
4918
+ $.fancybox.close();
4919
+
4920
+ shouldCreateHistory = true;
4921
+ }
4922
+
4923
+ } else if ( url.gallery !== '' ) {
4924
+ triggerFromUrl( url );
4925
+ }
4926
+ });
4927
+
4928
+ // Check current hash and trigger click event on matching element to start fancyBox, if needed
4929
+ triggerFromUrl( parseUrl() );
4930
+
4931
+ }, 50);
4932
+
4933
+ });
4934
+
4935
+
4936
+ }(document, window, window.jQuery));