promethee 1.6.60 → 1.6.61

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/promethee.js +1 -1
  3. data/app/assets/stylesheets/promethee.sass +1 -1
  4. data/app/views/promethee/show/_image.srcset.html.erb +1 -1
  5. data/lib/promethee/rails/version.rb +1 -1
  6. data/node_modules/@fancyapps/fancybox/README.md +62 -0
  7. data/node_modules/@fancyapps/fancybox/bower.json +23 -0
  8. data/node_modules/@fancyapps/fancybox/dist/jquery.fancybox.css +770 -0
  9. data/node_modules/@fancyapps/fancybox/dist/jquery.fancybox.js +5138 -0
  10. data/node_modules/@fancyapps/fancybox/dist/jquery.fancybox.min.css +1 -0
  11. data/node_modules/@fancyapps/fancybox/dist/jquery.fancybox.min.js +12 -0
  12. data/node_modules/@fancyapps/fancybox/docs/index.html +1923 -0
  13. data/node_modules/@fancyapps/fancybox/gulpfile.js +67 -0
  14. data/node_modules/@fancyapps/fancybox/package.json +80 -0
  15. data/node_modules/@fancyapps/fancybox/src/css/core.css +634 -0
  16. data/node_modules/@fancyapps/fancybox/src/css/fullscreen.css +11 -0
  17. data/node_modules/@fancyapps/fancybox/src/css/share.css +96 -0
  18. data/node_modules/@fancyapps/fancybox/src/css/slideshow.css +26 -0
  19. data/node_modules/@fancyapps/fancybox/src/css/thumbs.css +120 -0
  20. data/node_modules/@fancyapps/fancybox/src/js/core.js +3064 -0
  21. data/node_modules/@fancyapps/fancybox/src/js/fullscreen.js +169 -0
  22. data/node_modules/@fancyapps/fancybox/src/js/guestures.js +885 -0
  23. data/node_modules/@fancyapps/fancybox/src/js/hash.js +216 -0
  24. data/node_modules/@fancyapps/fancybox/src/js/media.js +201 -0
  25. data/node_modules/@fancyapps/fancybox/src/js/share.js +104 -0
  26. data/node_modules/@fancyapps/fancybox/src/js/slideshow.js +181 -0
  27. data/node_modules/@fancyapps/fancybox/src/js/thumbs.js +259 -0
  28. data/node_modules/@fancyapps/fancybox/src/js/wheel.js +41 -0
  29. metadata +24 -1
@@ -0,0 +1,11 @@
1
+
2
+ /* Fullscreen */
3
+
4
+ .fancybox-button--fullscreen::before {
5
+ width: 15px;
6
+ height: 11px;
7
+ left: calc(50% - 7px);
8
+ top: calc(50% - 6px);
9
+ border: 2px solid;
10
+ background: none;
11
+ }
@@ -0,0 +1,96 @@
1
+ /* Share */
2
+
3
+ .fancybox-share {
4
+ background: #f4f4f4;
5
+ border-radius: 3px;
6
+ max-width: 90%;
7
+ padding: 30px;
8
+ text-align: center;
9
+ }
10
+
11
+ .fancybox-share h1 {
12
+ color: #222;
13
+ font-size: 35px;
14
+ font-weight: 700;
15
+ margin: 0 0 20px 0;
16
+ }
17
+
18
+ .fancybox-share p {
19
+ margin: 0;
20
+ padding: 0;
21
+ }
22
+
23
+ .fancybox-share__button {
24
+ border: 0;
25
+ border-radius: 3px;
26
+ display: inline-block;
27
+ font-size: 14px;
28
+ font-weight: 700;
29
+ line-height: 40px;
30
+ margin: 0 5px 10px 5px;
31
+ min-width: 130px;
32
+ padding: 0 15px;
33
+ text-decoration: none;
34
+ transition: all .2s;
35
+ user-select: none;
36
+ white-space: nowrap;
37
+ }
38
+
39
+ .fancybox-share__button:visited,
40
+ .fancybox-share__button:link {
41
+ color: #fff;
42
+ }
43
+
44
+ .fancybox-share__button:hover {
45
+ text-decoration: none;
46
+ }
47
+
48
+ .fancybox-share__button--fb {
49
+ background: #3b5998;
50
+ }
51
+
52
+ .fancybox-share__button--fb:hover {
53
+ background: #344e86;
54
+ }
55
+
56
+ .fancybox-share__button--pt {
57
+ background: #bd081d;
58
+ }
59
+
60
+ .fancybox-share__button--pt:hover {
61
+ background: #aa0719;
62
+ }
63
+
64
+ .fancybox-share__button--tw {
65
+ background: #1da1f2;
66
+ }
67
+
68
+ .fancybox-share__button--tw:hover {
69
+ background: #0d95e8;
70
+ }
71
+
72
+ .fancybox-share__button svg {
73
+ height: 25px;
74
+ margin-right: 7px;
75
+ position: relative;
76
+ top: -1px;
77
+ vertical-align: middle;
78
+ width: 25px;
79
+ }
80
+
81
+ .fancybox-share__button svg path {
82
+ fill: #fff;
83
+ }
84
+
85
+ .fancybox-share__input {
86
+ background: transparent;
87
+ border: 0;
88
+ border-bottom: 1px solid #d7d7d7;
89
+ border-radius: 0;
90
+ color: #5d5b5b;
91
+ font-size: 14px;
92
+ margin: 10px 0 0 0;
93
+ outline: none;
94
+ padding: 10px 15px;
95
+ width: 100%;
96
+ }
@@ -0,0 +1,26 @@
1
+ /* Slideshow button */
2
+
3
+ .fancybox-button--play {}
4
+
5
+ .fancybox-button--play::before,
6
+ .fancybox-button--pause::before {
7
+ top: calc(50% - 6px);
8
+ left: calc(50% - 4px);
9
+ background: transparent;
10
+ }
11
+
12
+ .fancybox-button--play::before {
13
+ width: 0;
14
+ height: 0;
15
+ border-top: 6px inset transparent;
16
+ border-bottom: 6px inset transparent;
17
+ border-left: 10px solid;
18
+ border-radius: 1px;
19
+ }
20
+
21
+ .fancybox-button--pause::before {
22
+ width: 7px;
23
+ height: 11px;
24
+ border-style: solid;
25
+ border-width: 0 2px 0 2px;
26
+ }
@@ -0,0 +1,120 @@
1
+ /* Thumbs */
2
+
3
+ .fancybox-thumbs {
4
+ background: #fff;
5
+ bottom: 0;
6
+ display: none;
7
+ margin: 0;
8
+ -webkit-overflow-scrolling: touch;
9
+ -ms-overflow-style: -ms-autohiding-scrollbar;
10
+ padding: 2px 2px 4px 2px;
11
+ position: absolute;
12
+ right: 0;
13
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
14
+ top: 0;
15
+ width: 212px;
16
+ z-index: 99995;
17
+ }
18
+
19
+ .fancybox-thumbs-x {
20
+ overflow-x: auto;
21
+ overflow-y: hidden;
22
+ }
23
+
24
+ .fancybox-show-thumbs .fancybox-thumbs {
25
+ display: block;
26
+ }
27
+
28
+ .fancybox-show-thumbs .fancybox-inner {
29
+ right: 212px;
30
+ }
31
+
32
+ .fancybox-thumbs > ul {
33
+ font-size: 0;
34
+ height: 100%;
35
+ list-style: none;
36
+ margin: 0;
37
+ overflow-x: hidden;
38
+ overflow-y: auto;
39
+ padding: 0;
40
+ position: absolute;
41
+ position: relative;
42
+ white-space: nowrap;
43
+ width: 100%;
44
+ }
45
+
46
+ .fancybox-thumbs-x > ul {
47
+ overflow: hidden;
48
+ }
49
+
50
+ .fancybox-thumbs-y > ul::-webkit-scrollbar {
51
+ width: 7px;
52
+ }
53
+
54
+ .fancybox-thumbs-y > ul::-webkit-scrollbar-track {
55
+ background: #fff;
56
+ border-radius: 10px;
57
+ box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
58
+ }
59
+
60
+ .fancybox-thumbs-y > ul::-webkit-scrollbar-thumb {
61
+ background: #2a2a2a;
62
+ border-radius: 10px;
63
+ }
64
+
65
+ .fancybox-thumbs > ul > li {
66
+ backface-visibility: hidden;
67
+ cursor: pointer;
68
+ float: left;
69
+ height: 75px;
70
+ margin: 2px;
71
+ max-height: calc(100% - 8px);
72
+ max-width: calc(50% - 4px);
73
+ outline: none;
74
+ overflow: hidden;
75
+ padding: 0;
76
+ position: relative;
77
+ -webkit-tap-highlight-color: transparent;
78
+ width: 100px;
79
+ }
80
+
81
+ .fancybox-thumbs-loading {
82
+ background: rgba(0, 0, 0, .1);
83
+ }
84
+
85
+ .fancybox-thumbs > ul > li {
86
+ background-position: center center;
87
+ background-repeat: no-repeat;
88
+ background-size: cover;
89
+ }
90
+
91
+ .fancybox-thumbs > ul > li:before {
92
+ border: 4px solid #4ea7f9;
93
+ bottom: 0;
94
+ content: '';
95
+ left: 0;
96
+ opacity: 0;
97
+ position: absolute;
98
+ right: 0;
99
+ top: 0;
100
+ transition: all .2s cubic-bezier(.25, .46, .45, .94);
101
+ z-index: 99991;
102
+ }
103
+
104
+ .fancybox-thumbs .fancybox-thumbs-active:before {
105
+ opacity: 1;
106
+ }
107
+
108
+ /* Styling for Small-Screen Devices */
109
+
110
+ @media all and (max-width: 800px) {
111
+ .fancybox-thumbs {
112
+ width: 110px;
113
+ }
114
+ .fancybox-show-thumbs .fancybox-inner {
115
+ right: 110px;
116
+ }
117
+ .fancybox-thumbs > ul > li {
118
+ max-width: calc(100% - 10px);
119
+ }
120
+ }
@@ -0,0 +1,3064 @@
1
+ (function(window, document, $, undefined) {
2
+ "use strict";
3
+
4
+ window.console = window.console || {
5
+ info: function(stuff) {}
6
+ };
7
+
8
+ // If there's no jQuery, fancyBox can't work
9
+ // =========================================
10
+
11
+ if (!$) {
12
+ return;
13
+ }
14
+
15
+ // Check if fancyBox is already initialized
16
+ // ========================================
17
+
18
+ if ($.fn.fancybox) {
19
+ console.info("fancyBox already initialized");
20
+
21
+ return;
22
+ }
23
+
24
+ // Private default settings
25
+ // ========================
26
+
27
+ var defaults = {
28
+ // Enable infinite gallery navigation
29
+ loop: false,
30
+
31
+ // Horizontal space between slides
32
+ gutter: 50,
33
+
34
+ // Enable keyboard navigation
35
+ keyboard: true,
36
+
37
+ // Should display navigation arrows at the screen edges
38
+ arrows: true,
39
+
40
+ // Should display counter at the top left corner
41
+ infobar: true,
42
+
43
+ // Should display close button (using `btnTpl.smallBtn` template) over the content
44
+ // Can be true, false, "auto"
45
+ // If "auto" - will be automatically enabled for "html", "inline" or "ajax" items
46
+ smallBtn: "auto",
47
+
48
+ // Should display toolbar (buttons at the top)
49
+ // Can be true, false, "auto"
50
+ // If "auto" - will be automatically hidden if "smallBtn" is enabled
51
+ toolbar: "auto",
52
+
53
+ // What buttons should appear in the top right corner.
54
+ // Buttons will be created using templates from `btnTpl` option
55
+ // and they will be placed into toolbar (class="fancybox-toolbar"` element)
56
+ buttons: [
57
+ "zoom",
58
+ //"share",
59
+ //"slideShow",
60
+ //"fullScreen",
61
+ //"download",
62
+ "thumbs",
63
+ "close"
64
+ ],
65
+
66
+ // Detect "idle" time in seconds
67
+ idleTime: 3,
68
+
69
+ // Disable right-click and use simple image protection for images
70
+ protect: false,
71
+
72
+ // Shortcut to make content "modal" - disable keyboard navigtion, hide buttons, etc
73
+ modal: false,
74
+
75
+ image: {
76
+ // Wait for images to load before displaying
77
+ // true - wait for image to load and then display;
78
+ // false - display thumbnail and load the full-sized image over top,
79
+ // requires predefined image dimensions (`data-width` and `data-height` attributes)
80
+ preload: false
81
+ },
82
+
83
+ ajax: {
84
+ // Object containing settings for ajax request
85
+ settings: {
86
+ // This helps to indicate that request comes from the modal
87
+ // Feel free to change naming
88
+ data: {
89
+ fancybox: true
90
+ }
91
+ }
92
+ },
93
+
94
+ iframe: {
95
+ // Iframe template
96
+ tpl:
97
+ '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" src=""></iframe>',
98
+
99
+ // Preload iframe before displaying it
100
+ // This allows to calculate iframe content width and height
101
+ // (note: Due to "Same Origin Policy", you can't get cross domain data).
102
+ preload: true,
103
+
104
+ // Custom CSS styling for iframe wrapping element
105
+ // You can use this to set custom iframe dimensions
106
+ css: {},
107
+
108
+ // Iframe tag attributes
109
+ attr: {
110
+ scrolling: "auto"
111
+ }
112
+ },
113
+
114
+ // Default content type if cannot be detected automatically
115
+ defaultType: "image",
116
+
117
+ // Open/close animation type
118
+ // Possible values:
119
+ // false - disable
120
+ // "zoom" - zoom images from/to thumbnail
121
+ // "fade"
122
+ // "zoom-in-out"
123
+ //
124
+ animationEffect: "zoom",
125
+
126
+ // Duration in ms for open/close animation
127
+ animationDuration: 366,
128
+
129
+ // Should image change opacity while zooming
130
+ // If opacity is "auto", then opacity will be changed if image and thumbnail have different aspect ratios
131
+ zoomOpacity: "auto",
132
+
133
+ // Transition effect between slides
134
+ //
135
+ // Possible values:
136
+ // false - disable
137
+ // "fade'
138
+ // "slide'
139
+ // "circular'
140
+ // "tube'
141
+ // "zoom-in-out'
142
+ // "rotate'
143
+ //
144
+ transitionEffect: "fade",
145
+
146
+ // Duration in ms for transition animation
147
+ transitionDuration: 366,
148
+
149
+ // Custom CSS class for slide element
150
+ slideClass: "",
151
+
152
+ // Custom CSS class for layout
153
+ baseClass: "",
154
+
155
+ // Base template for layout
156
+ baseTpl:
157
+ '<div class="fancybox-container" role="dialog" tabindex="-1">' +
158
+ '<div class="fancybox-bg"></div>' +
159
+ '<div class="fancybox-inner">' +
160
+ '<div class="fancybox-infobar">' +
161
+ "<span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span>" +
162
+ "</div>" +
163
+ '<div class="fancybox-toolbar">{{buttons}}</div>' +
164
+ '<div class="fancybox-navigation">{{arrows}}</div>' +
165
+ '<div class="fancybox-stage"></div>' +
166
+ '<div class="fancybox-caption"></div>' +
167
+ "</div>" +
168
+ "</div>",
169
+
170
+ // Loading indicator template
171
+ spinnerTpl: '<div class="fancybox-loading"></div>',
172
+
173
+ // Error message template
174
+ errorTpl: '<div class="fancybox-error"><p>{{ERROR}}</p></div>',
175
+
176
+ btnTpl: {
177
+ download:
178
+ '<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}" href="javascript:;">' +
179
+ '<svg viewBox="0 0 40 40">' +
180
+ '<path d="M13,16 L20,23 L27,16 M20,7 L20,23 M10,24 L10,28 L30,28 L30,24" />' +
181
+ "</svg>" +
182
+ "</a>",
183
+
184
+ zoom:
185
+ '<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}">' +
186
+ '<svg viewBox="0 0 40 40">' +
187
+ '<path d="M18,17 m-8,0 a8,8 0 1,0 16,0 a8,8 0 1,0 -16,0 M24,22 L31,29" />' +
188
+ "</svg>" +
189
+ "</button>",
190
+
191
+ close:
192
+ '<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}">' +
193
+ '<svg viewBox="0 0 40 40">' +
194
+ '<path d="M10,10 L30,30 M30,10 L10,30" />' +
195
+ "</svg>" +
196
+ "</button>",
197
+
198
+ // This small close button will be appended to your html/inline/ajax content by default,
199
+ // if "smallBtn" option is not set to false
200
+ smallBtn:
201
+ '<button data-fancybox-close class="fancybox-close-small" title="{{CLOSE}}"><svg viewBox="0 0 32 32"><path d="M10,10 L22,22 M22,10 L10,22"></path></svg></button>',
202
+
203
+ // Arrows
204
+ arrowLeft:
205
+ '<a data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}" href="javascript:;">' +
206
+ '<svg viewBox="0 0 40 40">' +
207
+ '<path d="M18,12 L10,20 L18,28 M10,20 L30,20"></path>' +
208
+ "</svg>" +
209
+ "</a>",
210
+
211
+ arrowRight:
212
+ '<a data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}" href="javascript:;">' +
213
+ '<svg viewBox="0 0 40 40">' +
214
+ '<path d="M10,20 L30,20 M22,12 L30,20 L22,28"></path>' +
215
+ "</svg>" +
216
+ "</a>"
217
+ },
218
+
219
+ // Container is injected into this element
220
+ parentEl: "body",
221
+
222
+ // Focus handling
223
+ // ==============
224
+
225
+ // Try to focus on the first focusable element after opening
226
+ autoFocus: false,
227
+
228
+ // Put focus back to active element after closing
229
+ backFocus: true,
230
+
231
+ // Do not let user to focus on element outside modal content
232
+ trapFocus: true,
233
+
234
+ // Module specific options
235
+ // =======================
236
+
237
+ fullScreen: {
238
+ autoStart: false
239
+ },
240
+
241
+ // Set `touch: false` to disable dragging/swiping
242
+ touch: {
243
+ vertical: true, // Allow to drag content vertically
244
+ momentum: true // Continue movement after releasing mouse/touch when panning
245
+ },
246
+
247
+ // Hash value when initializing manually,
248
+ // set `false` to disable hash change
249
+ hash: null,
250
+
251
+ // Customize or add new media types
252
+ // Example:
253
+ /*
254
+ media : {
255
+ youtube : {
256
+ params : {
257
+ autoplay : 0
258
+ }
259
+ }
260
+ }
261
+ */
262
+ media: {},
263
+
264
+ slideShow: {
265
+ autoStart: false,
266
+ speed: 4000
267
+ },
268
+
269
+ thumbs: {
270
+ autoStart: false, // Display thumbnails on opening
271
+ hideOnClose: true, // Hide thumbnail grid when closing animation starts
272
+ parentEl: ".fancybox-container", // Container is injected into this element
273
+ axis: "y" // Vertical (y) or horizontal (x) scrolling
274
+ },
275
+
276
+ // Use mousewheel to navigate gallery
277
+ // If 'auto' - enabled for images only
278
+ wheel: "auto",
279
+
280
+ // Callbacks
281
+ //==========
282
+
283
+ // See Documentation/API/Events for more information
284
+ // Example:
285
+ /*
286
+ afterShow: function( instance, current ) {
287
+ console.info( 'Clicked element:' );
288
+ console.info( current.opts.$orig );
289
+ }
290
+ */
291
+
292
+ onInit: $.noop, // When instance has been initialized
293
+
294
+ beforeLoad: $.noop, // Before the content of a slide is being loaded
295
+ afterLoad: $.noop, // When the content of a slide is done loading
296
+
297
+ beforeShow: $.noop, // Before open animation starts
298
+ afterShow: $.noop, // When content is done loading and animating
299
+
300
+ beforeClose: $.noop, // Before the instance attempts to close. Return false to cancel the close.
301
+ afterClose: $.noop, // After instance has been closed
302
+
303
+ onActivate: $.noop, // When instance is brought to front
304
+ onDeactivate: $.noop, // When other instance has been activated
305
+
306
+ // Interaction
307
+ // ===========
308
+
309
+ // Use options below to customize taken action when user clicks or double clicks on the fancyBox area,
310
+ // each option can be string or method that returns value.
311
+ //
312
+ // Possible values:
313
+ // "close" - close instance
314
+ // "next" - move to next gallery item
315
+ // "nextOrClose" - move to next gallery item or close if gallery has only one item
316
+ // "toggleControls" - show/hide controls
317
+ // "zoom" - zoom image (if loaded)
318
+ // false - do nothing
319
+
320
+ // Clicked on the content
321
+ clickContent: function(current, event) {
322
+ return current.type === "image" ? "zoom" : false;
323
+ },
324
+
325
+ // Clicked on the slide
326
+ clickSlide: "close",
327
+
328
+ // Clicked on the background (backdrop) element;
329
+ // if you have not changed the layout, then most likely you need to use `clickSlide` option
330
+ clickOutside: "close",
331
+
332
+ // Same as previous two, but for double click
333
+ dblclickContent: false,
334
+ dblclickSlide: false,
335
+ dblclickOutside: false,
336
+
337
+ // Custom options when mobile device is detected
338
+ // =============================================
339
+
340
+ mobile: {
341
+ idleTime: false,
342
+ clickContent: function(current, event) {
343
+ return current.type === "image" ? "toggleControls" : false;
344
+ },
345
+ clickSlide: function(current, event) {
346
+ return current.type === "image" ? "toggleControls" : "close";
347
+ },
348
+ dblclickContent: function(current, event) {
349
+ return current.type === "image" ? "zoom" : false;
350
+ },
351
+ dblclickSlide: function(current, event) {
352
+ return current.type === "image" ? "zoom" : false;
353
+ }
354
+ },
355
+
356
+ // Internationalization
357
+ // ====================
358
+
359
+ lang: "en",
360
+ i18n: {
361
+ en: {
362
+ CLOSE: "Close",
363
+ NEXT: "Next",
364
+ PREV: "Previous",
365
+ ERROR: "The requested content cannot be loaded. <br/> Please try again later.",
366
+ PLAY_START: "Start slideshow",
367
+ PLAY_STOP: "Pause slideshow",
368
+ FULL_SCREEN: "Full screen",
369
+ THUMBS: "Thumbnails",
370
+ DOWNLOAD: "Download",
371
+ SHARE: "Share",
372
+ ZOOM: "Zoom"
373
+ },
374
+ de: {
375
+ CLOSE: "Schliessen",
376
+ NEXT: "Weiter",
377
+ PREV: "Zurück",
378
+ ERROR: "Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es später nochmal.",
379
+ PLAY_START: "Diaschau starten",
380
+ PLAY_STOP: "Diaschau beenden",
381
+ FULL_SCREEN: "Vollbild",
382
+ THUMBS: "Vorschaubilder",
383
+ DOWNLOAD: "Herunterladen",
384
+ SHARE: "Teilen",
385
+ ZOOM: "Maßstab"
386
+ }
387
+ }
388
+ };
389
+
390
+ // Few useful variables and methods
391
+ // ================================
392
+
393
+ var $W = $(window);
394
+ var $D = $(document);
395
+
396
+ var called = 0;
397
+
398
+ // Check if an object is a jQuery object and not a native JavaScript object
399
+ // ========================================================================
400
+ var isQuery = function(obj) {
401
+ return obj && obj.hasOwnProperty && obj instanceof $;
402
+ };
403
+
404
+ // Handle multiple browsers for "requestAnimationFrame" and "cancelAnimationFrame"
405
+ // ===============================================================================
406
+ var requestAFrame = (function() {
407
+ return (
408
+ window.requestAnimationFrame ||
409
+ window.webkitRequestAnimationFrame ||
410
+ window.mozRequestAnimationFrame ||
411
+ window.oRequestAnimationFrame ||
412
+ // if all else fails, use setTimeout
413
+ function(callback) {
414
+ return window.setTimeout(callback, 1000 / 60);
415
+ }
416
+ );
417
+ })();
418
+
419
+ // Detect the supported transition-end event property name
420
+ // =======================================================
421
+ var transitionEnd = (function() {
422
+ var el = document.createElement("fakeelement"),
423
+ t;
424
+
425
+ var transitions = {
426
+ transition: "transitionend",
427
+ OTransition: "oTransitionEnd",
428
+ MozTransition: "transitionend",
429
+ WebkitTransition: "webkitTransitionEnd"
430
+ };
431
+
432
+ for (t in transitions) {
433
+ if (el.style[t] !== undefined) {
434
+ return transitions[t];
435
+ }
436
+ }
437
+
438
+ return "transitionend";
439
+ })();
440
+
441
+ // Force redraw on an element.
442
+ // This helps in cases where the browser doesn't redraw an updated element properly
443
+ // ================================================================================
444
+ var forceRedraw = function($el) {
445
+ return $el && $el.length && $el[0].offsetHeight;
446
+ };
447
+
448
+ // Exclude array (`buttons`) options from deep merging
449
+ // ===================================================
450
+ var mergeOpts = function(opts1, opts2) {
451
+ var rez = $.extend(true, {}, opts1, opts2);
452
+
453
+ $.each(opts2, function(key, value) {
454
+ if ($.isArray(value)) {
455
+ rez[key] = value;
456
+ }
457
+ });
458
+
459
+ return rez;
460
+ };
461
+
462
+ // Class definition
463
+ // ================
464
+
465
+ var FancyBox = function(content, opts, index) {
466
+ var self = this;
467
+
468
+ self.opts = mergeOpts({index: index}, $.fancybox.defaults);
469
+
470
+ if ($.isPlainObject(opts)) {
471
+ self.opts = mergeOpts(self.opts, opts);
472
+ }
473
+
474
+ if ($.fancybox.isMobile) {
475
+ self.opts = mergeOpts(self.opts, self.opts.mobile);
476
+ }
477
+
478
+ self.id = self.opts.id || ++called;
479
+
480
+ self.currIndex = parseInt(self.opts.index, 10) || 0;
481
+ self.prevIndex = null;
482
+
483
+ self.prevPos = null;
484
+ self.currPos = 0;
485
+
486
+ self.firstRun = true;
487
+
488
+ // All group items
489
+ self.group = [];
490
+
491
+ // Existing slides (for current, next and previous gallery items)
492
+ self.slides = {};
493
+
494
+ // Create group elements
495
+ self.addContent(content);
496
+
497
+ if (!self.group.length) {
498
+ return;
499
+ }
500
+
501
+ // Save last active element
502
+ self.$lastFocus = $(document.activeElement).trigger("blur");
503
+
504
+ self.init();
505
+ };
506
+
507
+ $.extend(FancyBox.prototype, {
508
+ // Create DOM structure
509
+ // ====================
510
+
511
+ init: function() {
512
+ var self = this,
513
+ firstItem = self.group[self.currIndex],
514
+ firstItemOpts = firstItem.opts,
515
+ scrollbarWidth = $.fancybox.scrollbarWidth,
516
+ $scrollDiv,
517
+ $container,
518
+ buttonStr;
519
+
520
+ // Hide scrollbars
521
+ // ===============
522
+
523
+ if (!$.fancybox.getInstance() && firstItemOpts.hideScrollbar !== false) {
524
+ $("body").addClass("fancybox-active");
525
+
526
+ if (!$.fancybox.isMobile && document.body.scrollHeight > window.innerHeight) {
527
+ if (scrollbarWidth === undefined) {
528
+ $scrollDiv = $('<div style="width:100px;height:100px;overflow:scroll;" />').appendTo("body");
529
+
530
+ scrollbarWidth = $.fancybox.scrollbarWidth = $scrollDiv[0].offsetWidth - $scrollDiv[0].clientWidth;
531
+
532
+ $scrollDiv.remove();
533
+ }
534
+
535
+ $("head").append(
536
+ '<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar { margin-right: ' +
537
+ scrollbarWidth +
538
+ "px; }</style>"
539
+ );
540
+
541
+ $("body").addClass("compensate-for-scrollbar");
542
+ }
543
+ }
544
+
545
+ // Build html markup and set references
546
+ // ====================================
547
+
548
+ // Build html code for buttons and insert into main template
549
+ buttonStr = "";
550
+
551
+ $.each(firstItemOpts.buttons, function(index, value) {
552
+ buttonStr += firstItemOpts.btnTpl[value] || "";
553
+ });
554
+
555
+ // Create markup from base template, it will be initially hidden to
556
+ // avoid unnecessary work like painting while initializing is not complete
557
+ $container = $(
558
+ self.translate(
559
+ self,
560
+ firstItemOpts.baseTpl
561
+ .replace("{{buttons}}", buttonStr)
562
+ .replace("{{arrows}}", firstItemOpts.btnTpl.arrowLeft + firstItemOpts.btnTpl.arrowRight)
563
+ )
564
+ )
565
+ .attr("id", "fancybox-container-" + self.id)
566
+ .addClass("fancybox-is-hidden")
567
+ .addClass(firstItemOpts.baseClass)
568
+ .data("FancyBox", self)
569
+ .appendTo(firstItemOpts.parentEl);
570
+
571
+ // Create object holding references to jQuery wrapped nodes
572
+ self.$refs = {
573
+ container: $container
574
+ };
575
+
576
+ ["bg", "inner", "infobar", "toolbar", "stage", "caption", "navigation"].forEach(function(item) {
577
+ self.$refs[item] = $container.find(".fancybox-" + item);
578
+ });
579
+
580
+ self.trigger("onInit");
581
+
582
+ // Enable events, deactive previous instances
583
+ self.activate();
584
+
585
+ // Build slides, load and reveal content
586
+ self.jumpTo(self.currIndex);
587
+ },
588
+
589
+ // Simple i18n support - replaces object keys found in template
590
+ // with corresponding values
591
+ // ============================================================
592
+
593
+ translate: function(obj, str) {
594
+ var arr = obj.opts.i18n[obj.opts.lang];
595
+
596
+ return str.replace(/\{\{(\w+)\}\}/g, function(match, n) {
597
+ var value = arr[n];
598
+
599
+ if (value === undefined) {
600
+ return match;
601
+ }
602
+
603
+ return value;
604
+ });
605
+ },
606
+
607
+ // Populate current group with fresh content
608
+ // Check if each object has valid type and content
609
+ // ===============================================
610
+
611
+ addContent: function(content) {
612
+ var self = this,
613
+ items = $.makeArray(content),
614
+ thumbs;
615
+
616
+ $.each(items, function(i, item) {
617
+ var obj = {},
618
+ opts = {},
619
+ $item,
620
+ type,
621
+ found,
622
+ src,
623
+ srcParts;
624
+
625
+ // Step 1 - Make sure we have an object
626
+ // ====================================
627
+
628
+ if ($.isPlainObject(item)) {
629
+ // We probably have manual usage here, something like
630
+ // $.fancybox.open( [ { src : "image.jpg", type : "image" } ] )
631
+
632
+ obj = item;
633
+ opts = item.opts || item;
634
+ } else if ($.type(item) === "object" && $(item).length) {
635
+ // Here we probably have jQuery collection returned by some selector
636
+ $item = $(item);
637
+
638
+ // Support attributes like `data-options='{"touch" : false}'` and `data-touch='false'`
639
+ opts = $item.data() || {};
640
+ opts = $.extend(true, {}, opts, opts.options);
641
+
642
+ // Here we store clicked element
643
+ opts.$orig = $item;
644
+
645
+ obj.src = self.opts.src || opts.src || $item.attr("href");
646
+
647
+ // Assume that simple syntax is used, for example:
648
+ // `$.fancybox.open( $("#test"), {} );`
649
+ if (!obj.type && !obj.src) {
650
+ obj.type = "inline";
651
+ obj.src = item;
652
+ }
653
+ } else {
654
+ // Assume we have a simple html code, for example:
655
+ // $.fancybox.open( '<div><h1>Hi!</h1></div>' );
656
+ obj = {
657
+ type: "html",
658
+ src: item + ""
659
+ };
660
+ }
661
+
662
+ // Each gallery object has full collection of options
663
+ obj.opts = $.extend(true, {}, self.opts, opts);
664
+
665
+ // Do not merge buttons array
666
+ if ($.isArray(opts.buttons)) {
667
+ obj.opts.buttons = opts.buttons;
668
+ }
669
+
670
+ // Step 2 - Make sure we have content type, if not - try to guess
671
+ // ==============================================================
672
+
673
+ type = obj.type || obj.opts.type;
674
+ src = obj.src || "";
675
+
676
+ if (!type && src) {
677
+ if ((found = src.match(/\.(mp4|mov|ogv)((\?|#).*)?$/i))) {
678
+ type = "video";
679
+
680
+ if (!obj.opts.videoFormat) {
681
+ obj.opts.videoFormat = "video/" + (found[1] === "ogv" ? "ogg" : found[1]);
682
+ }
683
+ } else if (src.match(/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i)) {
684
+ type = "image";
685
+ } else if (src.match(/\.(pdf)((\?|#).*)?$/i)) {
686
+ type = "iframe";
687
+ } else if (src.charAt(0) === "#") {
688
+ type = "inline";
689
+ }
690
+ }
691
+
692
+ if (type) {
693
+ obj.type = type;
694
+ } else {
695
+ self.trigger("objectNeedsType", obj);
696
+ }
697
+
698
+ if (!obj.contentType) {
699
+ obj.contentType = $.inArray(obj.type, ["html", "inline", "ajax"]) > -1 ? "html" : obj.type;
700
+ }
701
+
702
+ // Step 3 - Some adjustments
703
+ // =========================
704
+
705
+ obj.index = self.group.length;
706
+
707
+ if (obj.opts.smallBtn == "auto") {
708
+ obj.opts.smallBtn = $.inArray(obj.type, ["html", "inline", "ajax"]) > -1;
709
+ }
710
+
711
+ if (obj.opts.toolbar === "auto") {
712
+ obj.opts.toolbar = !obj.opts.smallBtn;
713
+ }
714
+
715
+ // Find thumbnail image
716
+ if (obj.opts.$trigger && obj.index === self.opts.index) {
717
+ obj.opts.$thumb = obj.opts.$trigger.find("img:first");
718
+ }
719
+
720
+ if ((!obj.opts.$thumb || !obj.opts.$thumb.length) && obj.opts.$orig) {
721
+ obj.opts.$thumb = obj.opts.$orig.find("img:first");
722
+ }
723
+
724
+ // "caption" is a "special" option, it can be used to customize caption per gallery item ..
725
+ if ($.type(obj.opts.caption) === "function") {
726
+ obj.opts.caption = obj.opts.caption.apply(item, [self, obj]);
727
+ }
728
+
729
+ if ($.type(self.opts.caption) === "function") {
730
+ obj.opts.caption = self.opts.caption.apply(item, [self, obj]);
731
+ }
732
+
733
+ // Make sure we have caption as a string or jQuery object
734
+ if (!(obj.opts.caption instanceof $)) {
735
+ obj.opts.caption = obj.opts.caption === undefined ? "" : obj.opts.caption + "";
736
+ }
737
+
738
+ // Check if url contains "filter" used to filter the content
739
+ // Example: "ajax.html #something"
740
+ if (obj.type === "ajax") {
741
+ srcParts = src.split(/\s+/, 2);
742
+
743
+ if (srcParts.length > 1) {
744
+ obj.src = srcParts.shift();
745
+
746
+ obj.opts.filter = srcParts.shift();
747
+ }
748
+ }
749
+
750
+ // Hide all buttons and disable interactivity for modal items
751
+ if (obj.opts.modal) {
752
+ obj.opts = $.extend(true, obj.opts, {
753
+ // Remove buttons
754
+ infobar: 0,
755
+ toolbar: 0,
756
+
757
+ smallBtn: 0,
758
+
759
+ // Disable keyboard navigation
760
+ keyboard: 0,
761
+
762
+ // Disable some modules
763
+ slideShow: 0,
764
+ fullScreen: 0,
765
+ thumbs: 0,
766
+ touch: 0,
767
+
768
+ // Disable click event handlers
769
+ clickContent: false,
770
+ clickSlide: false,
771
+ clickOutside: false,
772
+ dblclickContent: false,
773
+ dblclickSlide: false,
774
+ dblclickOutside: false
775
+ });
776
+ }
777
+
778
+ // Step 4 - Add processed object to group
779
+ // ======================================
780
+
781
+ self.group.push(obj);
782
+ });
783
+
784
+ // Update controls if gallery is already opened
785
+ if (Object.keys(self.slides).length) {
786
+ self.updateControls();
787
+
788
+ // Update thumbnails, if needed
789
+ thumbs = self.Thumbs;
790
+
791
+ if (thumbs && thumbs.isActive) {
792
+ thumbs.create();
793
+
794
+ thumbs.focus();
795
+ }
796
+ }
797
+ },
798
+
799
+ // Attach an event handler functions for:
800
+ // - navigation buttons
801
+ // - browser scrolling, resizing;
802
+ // - focusing
803
+ // - keyboard
804
+ // - detect idle
805
+ // ======================================
806
+
807
+ addEvents: function() {
808
+ var self = this;
809
+
810
+ self.removeEvents();
811
+
812
+ // Make navigation elements clickable
813
+ self.$refs.container
814
+ .on("click.fb-close", "[data-fancybox-close]", function(e) {
815
+ e.stopPropagation();
816
+ e.preventDefault();
817
+
818
+ self.close(e);
819
+ })
820
+ .on("touchstart.fb-prev click.fb-prev", "[data-fancybox-prev]", function(e) {
821
+ e.stopPropagation();
822
+ e.preventDefault();
823
+
824
+ self.previous();
825
+ })
826
+ .on("touchstart.fb-next click.fb-next", "[data-fancybox-next]", function(e) {
827
+ e.stopPropagation();
828
+ e.preventDefault();
829
+
830
+ self.next();
831
+ })
832
+ .on("click.fb", "[data-fancybox-zoom]", function(e) {
833
+ // Click handler for zoom button
834
+ self[self.isScaledDown() ? "scaleToActual" : "scaleToFit"]();
835
+ });
836
+
837
+ // Handle page scrolling and browser resizing
838
+ $W.on("orientationchange.fb resize.fb", function(e) {
839
+ if (e && e.originalEvent && e.originalEvent.type === "resize") {
840
+ requestAFrame(function() {
841
+ self.update();
842
+ });
843
+ } else {
844
+ self.$refs.stage.hide();
845
+
846
+ setTimeout(function() {
847
+ self.$refs.stage.show();
848
+
849
+ self.update();
850
+ }, $.fancybox.isMobile ? 600 : 250);
851
+ }
852
+ });
853
+
854
+ // Trap keyboard focus inside of the modal, so the user does not accidentally tab outside of the modal
855
+ // (a.k.a. "escaping the modal")
856
+ $D.on("focusin.fb", function(e) {
857
+ var instance = $.fancybox ? $.fancybox.getInstance() : null;
858
+
859
+ if (
860
+ instance.isClosing ||
861
+ !instance.current ||
862
+ !instance.current.opts.trapFocus ||
863
+ $(e.target).hasClass("fancybox-container") ||
864
+ $(e.target).is(document)
865
+ ) {
866
+ return;
867
+ }
868
+
869
+ if (instance && $(e.target).css("position") !== "fixed" && !instance.$refs.container.has(e.target).length) {
870
+ e.stopPropagation();
871
+
872
+ instance.focus();
873
+ }
874
+ });
875
+
876
+ // Enable keyboard navigation
877
+ $D.on("keydown.fb", function(e) {
878
+ var current = self.current,
879
+ keycode = e.keyCode || e.which;
880
+
881
+ if (!current || !current.opts.keyboard) {
882
+ return;
883
+ }
884
+
885
+ if (e.ctrlKey || e.altKey || e.shiftKey || $(e.target).is("input") || $(e.target).is("textarea")) {
886
+ return;
887
+ }
888
+
889
+ // Backspace and Esc keys
890
+ if (keycode === 8 || keycode === 27) {
891
+ e.preventDefault();
892
+
893
+ self.close(e);
894
+
895
+ return;
896
+ }
897
+
898
+ // Left arrow and Up arrow
899
+ if (keycode === 37 || keycode === 38) {
900
+ e.preventDefault();
901
+
902
+ self.previous();
903
+
904
+ return;
905
+ }
906
+
907
+ // Righ arrow and Down arrow
908
+ if (keycode === 39 || keycode === 40) {
909
+ e.preventDefault();
910
+
911
+ self.next();
912
+
913
+ return;
914
+ }
915
+
916
+ self.trigger("afterKeydown", e, keycode);
917
+ });
918
+
919
+ // Hide controls after some inactivity period
920
+ if (self.group[self.currIndex].opts.idleTime) {
921
+ self.idleSecondsCounter = 0;
922
+
923
+ $D.on(
924
+ "mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle",
925
+ function(e) {
926
+ self.idleSecondsCounter = 0;
927
+
928
+ if (self.isIdle) {
929
+ self.showControls();
930
+ }
931
+
932
+ self.isIdle = false;
933
+ }
934
+ );
935
+
936
+ self.idleInterval = window.setInterval(function() {
937
+ self.idleSecondsCounter++;
938
+
939
+ if (self.idleSecondsCounter >= self.group[self.currIndex].opts.idleTime && !self.isDragging) {
940
+ self.isIdle = true;
941
+ self.idleSecondsCounter = 0;
942
+
943
+ self.hideControls();
944
+ }
945
+ }, 1000);
946
+ }
947
+ },
948
+
949
+ // Remove events added by the core
950
+ // ===============================
951
+
952
+ removeEvents: function() {
953
+ var self = this;
954
+
955
+ $W.off("orientationchange.fb resize.fb");
956
+ $D.off("focusin.fb keydown.fb .fb-idle");
957
+
958
+ this.$refs.container.off(".fb-close .fb-prev .fb-next");
959
+
960
+ if (self.idleInterval) {
961
+ window.clearInterval(self.idleInterval);
962
+
963
+ self.idleInterval = null;
964
+ }
965
+ },
966
+
967
+ // Change to previous gallery item
968
+ // ===============================
969
+
970
+ previous: function(duration) {
971
+ return this.jumpTo(this.currPos - 1, duration);
972
+ },
973
+
974
+ // Change to next gallery item
975
+ // ===========================
976
+
977
+ next: function(duration) {
978
+ return this.jumpTo(this.currPos + 1, duration);
979
+ },
980
+
981
+ // Switch to selected gallery item
982
+ // ===============================
983
+
984
+ jumpTo: function(pos, duration) {
985
+ var self = this,
986
+ groupLen = self.group.length,
987
+ firstRun,
988
+ loop,
989
+ current,
990
+ previous,
991
+ canvasWidth,
992
+ currentPos,
993
+ transitionProps;
994
+
995
+ if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) {
996
+ return;
997
+ }
998
+
999
+ pos = parseInt(pos, 10);
1000
+
1001
+ // Should loop?
1002
+ loop = self.current ? self.current.opts.loop : self.opts.loop;
1003
+
1004
+ if (!loop && (pos < 0 || pos >= groupLen)) {
1005
+ return false;
1006
+ }
1007
+
1008
+ firstRun = self.firstRun = !Object.keys(self.slides).length;
1009
+
1010
+ if (groupLen < 2 && !firstRun && !!self.isDragging) {
1011
+ return;
1012
+ }
1013
+
1014
+ previous = self.current;
1015
+
1016
+ self.prevIndex = self.currIndex;
1017
+ self.prevPos = self.currPos;
1018
+
1019
+ // Create slides
1020
+ current = self.createSlide(pos);
1021
+
1022
+ if (groupLen > 1) {
1023
+ if (loop || current.index > 0) {
1024
+ self.createSlide(pos - 1);
1025
+ }
1026
+
1027
+ if (loop || current.index < groupLen - 1) {
1028
+ self.createSlide(pos + 1);
1029
+ }
1030
+ }
1031
+
1032
+ self.current = current;
1033
+ self.currIndex = current.index;
1034
+ self.currPos = current.pos;
1035
+
1036
+ self.trigger("beforeShow", firstRun);
1037
+
1038
+ self.updateControls();
1039
+
1040
+ currentPos = $.fancybox.getTranslate(current.$slide);
1041
+
1042
+ current.isMoved = (currentPos.left !== 0 || currentPos.top !== 0) && !current.$slide.hasClass("fancybox-animated");
1043
+
1044
+ // Validate duration length
1045
+ current.forcedDuration = undefined;
1046
+
1047
+ if ($.isNumeric(duration)) {
1048
+ current.forcedDuration = duration;
1049
+ } else {
1050
+ duration = current.opts[firstRun ? "animationDuration" : "transitionDuration"];
1051
+ }
1052
+
1053
+ duration = parseInt(duration, 10);
1054
+
1055
+ // Fresh start - reveal container, current slide and start loading content
1056
+ if (firstRun) {
1057
+ if (current.opts.animationEffect && duration) {
1058
+ self.$refs.container.css("transition-duration", duration + "ms");
1059
+ }
1060
+
1061
+ self.$refs.container.removeClass("fancybox-is-hidden");
1062
+
1063
+ forceRedraw(self.$refs.container);
1064
+
1065
+ self.$refs.container.addClass("fancybox-is-open");
1066
+
1067
+ forceRedraw(self.$refs.container);
1068
+
1069
+ // Make current slide visible
1070
+ current.$slide.addClass("fancybox-slide--previous");
1071
+
1072
+ // Attempt to load content into slide;
1073
+ // at this point image would start loading, but inline/html content would load immediately
1074
+ self.loadSlide(current);
1075
+
1076
+ current.$slide.removeClass("fancybox-slide--previous").addClass("fancybox-slide--current");
1077
+
1078
+ self.preload("image");
1079
+
1080
+ return;
1081
+ }
1082
+
1083
+ // Clean up
1084
+ $.each(self.slides, function(index, slide) {
1085
+ $.fancybox.stop(slide.$slide);
1086
+ });
1087
+
1088
+ // Make current that slide is visible even if content is still loading
1089
+ current.$slide.removeClass("fancybox-slide--next fancybox-slide--previous").addClass("fancybox-slide--current");
1090
+
1091
+ // If slides have been dragged, animate them to correct position
1092
+ if (current.isMoved) {
1093
+ canvasWidth = Math.round(current.$slide.width());
1094
+
1095
+ $.each(self.slides, function(index, slide) {
1096
+ var pos = slide.pos - current.pos;
1097
+
1098
+ $.fancybox.animate(
1099
+ slide.$slide,
1100
+ {
1101
+ top: 0,
1102
+ left: pos * canvasWidth + pos * slide.opts.gutter
1103
+ },
1104
+ duration,
1105
+ function() {
1106
+ slide.$slide.removeAttr("style").removeClass("fancybox-slide--next fancybox-slide--previous");
1107
+
1108
+ if (slide.pos === self.currPos) {
1109
+ current.isMoved = false;
1110
+
1111
+ self.complete();
1112
+ }
1113
+ }
1114
+ );
1115
+ });
1116
+ } else {
1117
+ self.$refs.stage.children().removeAttr("style");
1118
+ }
1119
+
1120
+ // Start transition that reveals current content
1121
+ // or wait when it will be loaded
1122
+
1123
+ if (current.isLoaded) {
1124
+ self.revealContent(current);
1125
+ } else {
1126
+ self.loadSlide(current);
1127
+ }
1128
+
1129
+ self.preload("image");
1130
+
1131
+ if (previous.pos === current.pos) {
1132
+ return;
1133
+ }
1134
+
1135
+ // Handle previous slide
1136
+ // =====================
1137
+
1138
+ transitionProps = "fancybox-slide--" + (previous.pos > current.pos ? "next" : "previous");
1139
+
1140
+ previous.$slide.removeClass("fancybox-slide--complete fancybox-slide--current fancybox-slide--next fancybox-slide--previous");
1141
+
1142
+ previous.isComplete = false;
1143
+
1144
+ if (!duration || (!current.isMoved && !current.opts.transitionEffect)) {
1145
+ return;
1146
+ }
1147
+
1148
+ if (current.isMoved) {
1149
+ previous.$slide.addClass(transitionProps);
1150
+ } else {
1151
+ transitionProps = "fancybox-animated " + transitionProps + " fancybox-fx-" + current.opts.transitionEffect;
1152
+
1153
+ $.fancybox.animate(previous.$slide, transitionProps, duration, function() {
1154
+ previous.$slide.removeClass(transitionProps).removeAttr("style");
1155
+ });
1156
+ }
1157
+ },
1158
+
1159
+ // Create new "slide" element
1160
+ // These are gallery items that are actually added to DOM
1161
+ // =======================================================
1162
+
1163
+ createSlide: function(pos) {
1164
+ var self = this,
1165
+ $slide,
1166
+ index;
1167
+
1168
+ index = pos % self.group.length;
1169
+ index = index < 0 ? self.group.length + index : index;
1170
+
1171
+ if (!self.slides[pos] && self.group[index]) {
1172
+ $slide = $('<div class="fancybox-slide"></div>').appendTo(self.$refs.stage);
1173
+
1174
+ self.slides[pos] = $.extend(true, {}, self.group[index], {
1175
+ pos: pos,
1176
+ $slide: $slide,
1177
+ isLoaded: false
1178
+ });
1179
+
1180
+ self.updateSlide(self.slides[pos]);
1181
+ }
1182
+
1183
+ return self.slides[pos];
1184
+ },
1185
+
1186
+ // Scale image to the actual size of the image;
1187
+ // x and y values should be relative to the slide
1188
+ // ==============================================
1189
+
1190
+ scaleToActual: function(x, y, duration) {
1191
+ var self = this,
1192
+ current = self.current,
1193
+ $content = current.$content,
1194
+ canvasWidth = $.fancybox.getTranslate(current.$slide).width,
1195
+ canvasHeight = $.fancybox.getTranslate(current.$slide).height,
1196
+ newImgWidth = current.width,
1197
+ newImgHeight = current.height,
1198
+ imgPos,
1199
+ posX,
1200
+ posY,
1201
+ scaleX,
1202
+ scaleY;
1203
+
1204
+ if (self.isAnimating || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) {
1205
+ return;
1206
+ }
1207
+
1208
+ $.fancybox.stop($content);
1209
+
1210
+ self.isAnimating = true;
1211
+
1212
+ x = x === undefined ? canvasWidth * 0.5 : x;
1213
+ y = y === undefined ? canvasHeight * 0.5 : y;
1214
+
1215
+ imgPos = $.fancybox.getTranslate($content);
1216
+
1217
+ imgPos.top -= $.fancybox.getTranslate(current.$slide).top;
1218
+ imgPos.left -= $.fancybox.getTranslate(current.$slide).left;
1219
+
1220
+ scaleX = newImgWidth / imgPos.width;
1221
+ scaleY = newImgHeight / imgPos.height;
1222
+
1223
+ // Get center position for original image
1224
+ posX = canvasWidth * 0.5 - newImgWidth * 0.5;
1225
+ posY = canvasHeight * 0.5 - newImgHeight * 0.5;
1226
+
1227
+ // Make sure image does not move away from edges
1228
+ if (newImgWidth > canvasWidth) {
1229
+ posX = imgPos.left * scaleX - (x * scaleX - x);
1230
+
1231
+ if (posX > 0) {
1232
+ posX = 0;
1233
+ }
1234
+
1235
+ if (posX < canvasWidth - newImgWidth) {
1236
+ posX = canvasWidth - newImgWidth;
1237
+ }
1238
+ }
1239
+
1240
+ if (newImgHeight > canvasHeight) {
1241
+ posY = imgPos.top * scaleY - (y * scaleY - y);
1242
+
1243
+ if (posY > 0) {
1244
+ posY = 0;
1245
+ }
1246
+
1247
+ if (posY < canvasHeight - newImgHeight) {
1248
+ posY = canvasHeight - newImgHeight;
1249
+ }
1250
+ }
1251
+
1252
+ self.updateCursor(newImgWidth, newImgHeight);
1253
+
1254
+ $.fancybox.animate(
1255
+ $content,
1256
+ {
1257
+ top: posY,
1258
+ left: posX,
1259
+ scaleX: scaleX,
1260
+ scaleY: scaleY
1261
+ },
1262
+ duration || 330,
1263
+ function() {
1264
+ self.isAnimating = false;
1265
+ }
1266
+ );
1267
+
1268
+ // Stop slideshow
1269
+ if (self.SlideShow && self.SlideShow.isActive) {
1270
+ self.SlideShow.stop();
1271
+ }
1272
+ },
1273
+
1274
+ // Scale image to fit inside parent element
1275
+ // ========================================
1276
+
1277
+ scaleToFit: function(duration) {
1278
+ var self = this,
1279
+ current = self.current,
1280
+ $content = current.$content,
1281
+ end;
1282
+
1283
+ if (self.isAnimating || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) {
1284
+ return;
1285
+ }
1286
+
1287
+ $.fancybox.stop($content);
1288
+
1289
+ self.isAnimating = true;
1290
+
1291
+ end = self.getFitPos(current);
1292
+
1293
+ self.updateCursor(end.width, end.height);
1294
+
1295
+ $.fancybox.animate(
1296
+ $content,
1297
+ {
1298
+ top: end.top,
1299
+ left: end.left,
1300
+ scaleX: end.width / $content.width(),
1301
+ scaleY: end.height / $content.height()
1302
+ },
1303
+ duration || 330,
1304
+ function() {
1305
+ self.isAnimating = false;
1306
+ }
1307
+ );
1308
+ },
1309
+
1310
+ // Calculate image size to fit inside viewport
1311
+ // ===========================================
1312
+
1313
+ getFitPos: function(slide) {
1314
+ var self = this,
1315
+ $content = slide.$content,
1316
+ width = slide.width || slide.opts.width,
1317
+ height = slide.height || slide.opts.height,
1318
+ maxWidth,
1319
+ maxHeight,
1320
+ minRatio,
1321
+ margin,
1322
+ aspectRatio,
1323
+ rez = {};
1324
+
1325
+ if (!slide.isLoaded || !$content || !$content.length) {
1326
+ return false;
1327
+ }
1328
+
1329
+ margin = {
1330
+ top: parseInt(slide.$slide.css("paddingTop"), 10),
1331
+ right: parseInt(slide.$slide.css("paddingRight"), 10),
1332
+ bottom: parseInt(slide.$slide.css("paddingBottom"), 10),
1333
+ left: parseInt(slide.$slide.css("paddingLeft"), 10)
1334
+ };
1335
+
1336
+ // We can not use $slide width here, because it can have different diemensions while in transiton
1337
+ maxWidth = parseInt(self.$refs.stage.width(), 10) - (margin.left + margin.right);
1338
+ maxHeight = parseInt(self.$refs.stage.height(), 10) - (margin.top + margin.bottom);
1339
+
1340
+ if (!width || !height) {
1341
+ width = maxWidth;
1342
+ height = maxHeight;
1343
+ }
1344
+
1345
+ minRatio = Math.min(1, maxWidth / width, maxHeight / height);
1346
+
1347
+ // Use floor rounding to make sure it really fits
1348
+ width = Math.floor(minRatio * width);
1349
+ height = Math.floor(minRatio * height);
1350
+
1351
+ if (slide.type === "image") {
1352
+ rez.top = Math.floor((maxHeight - height) * 0.5) + margin.top;
1353
+ rez.left = Math.floor((maxWidth - width) * 0.5) + margin.left;
1354
+ } else if (slide.contentType === "video") {
1355
+ // Force aspect ratio for the video
1356
+ // "I say the whole world must learn of our peaceful ways… by force!"
1357
+ aspectRatio = slide.opts.width && slide.opts.height ? width / height : slide.opts.ratio || 16 / 9;
1358
+
1359
+ if (height > width / aspectRatio) {
1360
+ height = width / aspectRatio;
1361
+ } else if (width > height * aspectRatio) {
1362
+ width = height * aspectRatio;
1363
+ }
1364
+ }
1365
+
1366
+ rez.width = width;
1367
+ rez.height = height;
1368
+
1369
+ return rez;
1370
+ },
1371
+
1372
+ // Update content size and position for all slides
1373
+ // ==============================================
1374
+
1375
+ update: function() {
1376
+ var self = this;
1377
+
1378
+ $.each(self.slides, function(key, slide) {
1379
+ self.updateSlide(slide);
1380
+ });
1381
+ },
1382
+
1383
+ // Update slide content position and size
1384
+ // ======================================
1385
+
1386
+ updateSlide: function(slide, duration) {
1387
+ var self = this,
1388
+ $content = slide && slide.$content,
1389
+ width = slide.width || slide.opts.width,
1390
+ height = slide.height || slide.opts.height;
1391
+
1392
+ if ($content && (width || height || slide.contentType === "video") && !slide.hasError) {
1393
+ $.fancybox.stop($content);
1394
+
1395
+ $.fancybox.setTranslate($content, self.getFitPos(slide));
1396
+
1397
+ if (slide.pos === self.currPos) {
1398
+ self.isAnimating = false;
1399
+
1400
+ self.updateCursor();
1401
+ }
1402
+ }
1403
+
1404
+ slide.$slide.trigger("refresh");
1405
+
1406
+ self.$refs.toolbar.toggleClass("compensate-for-scrollbar", slide.$slide.get(0).scrollHeight > slide.$slide.get(0).clientHeight);
1407
+
1408
+ self.trigger("onUpdate", slide);
1409
+ },
1410
+
1411
+ // Horizontally center slide
1412
+ // =========================
1413
+
1414
+ centerSlide: function(slide, duration) {
1415
+ var self = this,
1416
+ canvasWidth,
1417
+ pos;
1418
+
1419
+ if (self.current) {
1420
+ canvasWidth = Math.round(slide.$slide.width());
1421
+ pos = slide.pos - self.current.pos;
1422
+
1423
+ $.fancybox.animate(
1424
+ slide.$slide,
1425
+ {
1426
+ top: 0,
1427
+ left: pos * canvasWidth + pos * slide.opts.gutter,
1428
+ opacity: 1
1429
+ },
1430
+ duration === undefined ? 0 : duration,
1431
+ null,
1432
+ false
1433
+ );
1434
+ }
1435
+ },
1436
+
1437
+ // Update cursor style depending if content can be zoomed
1438
+ // ======================================================
1439
+
1440
+ updateCursor: function(nextWidth, nextHeight) {
1441
+ var self = this,
1442
+ current = self.current,
1443
+ $container = self.$refs.container.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-drag fancybox-can-zoomOut"),
1444
+ isZoomable;
1445
+
1446
+ if (!current || self.isClosing) {
1447
+ return;
1448
+ }
1449
+
1450
+ isZoomable = self.isZoomable();
1451
+
1452
+ $container.toggleClass("fancybox-is-zoomable", isZoomable);
1453
+
1454
+ $("[data-fancybox-zoom]").prop("disabled", !isZoomable);
1455
+
1456
+ // Set cursor to zoom in/out if click event is 'zoom'
1457
+ if (
1458
+ isZoomable &&
1459
+ (current.opts.clickContent === "zoom" || ($.isFunction(current.opts.clickContent) && current.opts.clickContent(current) === "zoom"))
1460
+ ) {
1461
+ if (self.isScaledDown(nextWidth, nextHeight)) {
1462
+ // If image is scaled down, then, obviously, it can be zoomed to full size
1463
+ $container.addClass("fancybox-can-zoomIn");
1464
+ } else {
1465
+ if (current.opts.touch) {
1466
+ // If image size ir largen than available available and touch module is not disable,
1467
+ // then user can do panning
1468
+ $container.addClass("fancybox-can-drag");
1469
+ } else {
1470
+ $container.addClass("fancybox-can-zoomOut");
1471
+ }
1472
+ }
1473
+ } else if (current.opts.touch && current.contentType !== "video") {
1474
+ $container.addClass("fancybox-can-drag");
1475
+ }
1476
+ },
1477
+
1478
+ // Check if current slide is zoomable
1479
+ // ==================================
1480
+
1481
+ isZoomable: function() {
1482
+ var self = this,
1483
+ current = self.current,
1484
+ fitPos;
1485
+
1486
+ // Assume that slide is zoomable if:
1487
+ // - image is still loading
1488
+ // - actual size of the image is smaller than available area
1489
+ if (current && !self.isClosing && current.type === "image" && !current.hasError) {
1490
+ if (!current.isLoaded) {
1491
+ return true;
1492
+ }
1493
+
1494
+ fitPos = self.getFitPos(current);
1495
+
1496
+ if (current.width > fitPos.width || current.height > fitPos.height) {
1497
+ return true;
1498
+ }
1499
+ }
1500
+
1501
+ return false;
1502
+ },
1503
+
1504
+ // Check if current image dimensions are smaller than actual
1505
+ // =========================================================
1506
+
1507
+ isScaledDown: function(nextWidth, nextHeight) {
1508
+ var self = this,
1509
+ rez = false,
1510
+ current = self.current,
1511
+ $content = current.$content;
1512
+
1513
+ if (nextWidth !== undefined && nextHeight !== undefined) {
1514
+ rez = nextWidth < current.width && nextHeight < current.height;
1515
+ } else if ($content) {
1516
+ rez = $.fancybox.getTranslate($content);
1517
+ rez = rez.width < current.width && rez.height < current.height;
1518
+ }
1519
+
1520
+ return rez;
1521
+ },
1522
+
1523
+ // Check if image dimensions exceed parent element
1524
+ // ===============================================
1525
+
1526
+ canPan: function() {
1527
+ var self = this,
1528
+ rez = false,
1529
+ current = self.current,
1530
+ $content;
1531
+
1532
+ if (current.type === "image" && ($content = current.$content) && !current.hasError) {
1533
+ rez = self.getFitPos(current);
1534
+ rez = Math.abs($content.width() - rez.width) > 1 || Math.abs($content.height() - rez.height) > 1;
1535
+ }
1536
+
1537
+ return rez;
1538
+ },
1539
+
1540
+ // Load content into the slide
1541
+ // ===========================
1542
+
1543
+ loadSlide: function(slide) {
1544
+ var self = this,
1545
+ type,
1546
+ $slide,
1547
+ ajaxLoad;
1548
+
1549
+ if (slide.isLoading || slide.isLoaded) {
1550
+ return;
1551
+ }
1552
+
1553
+ slide.isLoading = true;
1554
+
1555
+ self.trigger("beforeLoad", slide);
1556
+
1557
+ type = slide.type;
1558
+ $slide = slide.$slide;
1559
+
1560
+ $slide
1561
+ .off("refresh")
1562
+ .trigger("onReset")
1563
+ .addClass(slide.opts.slideClass);
1564
+
1565
+ // Create content depending on the type
1566
+ switch (type) {
1567
+ case "image":
1568
+ self.setImage(slide);
1569
+
1570
+ break;
1571
+
1572
+ case "iframe":
1573
+ self.setIframe(slide);
1574
+
1575
+ break;
1576
+
1577
+ case "html":
1578
+ self.setContent(slide, slide.src || slide.content);
1579
+
1580
+ break;
1581
+
1582
+ case "video":
1583
+ self.setContent(
1584
+ slide,
1585
+ '<video class="fancybox-video" controls controlsList="nodownload">' +
1586
+ '<source src="' +
1587
+ slide.src +
1588
+ '" type="' +
1589
+ slide.opts.videoFormat +
1590
+ '">' +
1591
+ "Your browser doesn't support HTML5 video" +
1592
+ "</video"
1593
+ );
1594
+
1595
+ break;
1596
+
1597
+ case "inline":
1598
+ if ($(slide.src).length) {
1599
+ self.setContent(slide, $(slide.src));
1600
+ } else {
1601
+ self.setError(slide);
1602
+ }
1603
+
1604
+ break;
1605
+
1606
+ case "ajax":
1607
+ self.showLoading(slide);
1608
+
1609
+ ajaxLoad = $.ajax(
1610
+ $.extend({}, slide.opts.ajax.settings, {
1611
+ url: slide.src,
1612
+ success: function(data, textStatus) {
1613
+ if (textStatus === "success") {
1614
+ self.setContent(slide, data);
1615
+ }
1616
+ },
1617
+ error: function(jqXHR, textStatus) {
1618
+ if (jqXHR && textStatus !== "abort") {
1619
+ self.setError(slide);
1620
+ }
1621
+ }
1622
+ })
1623
+ );
1624
+
1625
+ $slide.one("onReset", function() {
1626
+ ajaxLoad.abort();
1627
+ });
1628
+
1629
+ break;
1630
+
1631
+ default:
1632
+ self.setError(slide);
1633
+
1634
+ break;
1635
+ }
1636
+
1637
+ return true;
1638
+ },
1639
+
1640
+ // Use thumbnail image, if possible
1641
+ // ================================
1642
+
1643
+ setImage: function(slide) {
1644
+ var self = this,
1645
+ srcset = slide.opts.srcset || slide.opts.image.srcset,
1646
+ thumbSrc,
1647
+ found,
1648
+ temp,
1649
+ pxRatio,
1650
+ windowWidth;
1651
+
1652
+ // Check if need to show loading icon
1653
+ slide.timouts = setTimeout(function() {
1654
+ var $img = slide.$image;
1655
+
1656
+ if (slide.isLoading && (!$img || !$img[0].complete) && !slide.hasError) {
1657
+ self.showLoading(slide);
1658
+ }
1659
+ }, 350);
1660
+
1661
+ // If we have "srcset", then we need to find first matching "src" value.
1662
+ // This is necessary, because when you set an src attribute, the browser will preload the image
1663
+ // before any javascript or even CSS is applied.
1664
+ if (srcset) {
1665
+ pxRatio = window.devicePixelRatio || 1;
1666
+ windowWidth = window.innerWidth * pxRatio;
1667
+
1668
+ temp = srcset.split(",").map(function(el) {
1669
+ var ret = {};
1670
+
1671
+ el
1672
+ .trim()
1673
+ .split(/\s+/)
1674
+ .forEach(function(el, i) {
1675
+ var value = parseInt(el.substring(0, el.length - 1), 10);
1676
+
1677
+ if (i === 0) {
1678
+ return (ret.url = el);
1679
+ }
1680
+
1681
+ if (value) {
1682
+ ret.value = value;
1683
+ ret.postfix = el[el.length - 1];
1684
+ }
1685
+ });
1686
+
1687
+ return ret;
1688
+ });
1689
+
1690
+ // Sort by value
1691
+ temp.sort(function(a, b) {
1692
+ return a.value - b.value;
1693
+ });
1694
+
1695
+ // Ok, now we have an array of all srcset values
1696
+ for (var j = 0; j < temp.length; j++) {
1697
+ var el = temp[j];
1698
+
1699
+ if ((el.postfix === "w" && el.value >= windowWidth) || (el.postfix === "x" && el.value >= pxRatio)) {
1700
+ found = el;
1701
+ break;
1702
+ }
1703
+ }
1704
+
1705
+ // If not found, take the last one
1706
+ if (!found && temp.length) {
1707
+ found = temp[temp.length - 1];
1708
+ }
1709
+
1710
+ if (found) {
1711
+ slide.src = found.url;
1712
+
1713
+ // If we have default width/height values, we can calculate height for matching source
1714
+ if (slide.width && slide.height && found.postfix == "w") {
1715
+ slide.height = slide.width / slide.height * found.value;
1716
+ slide.width = found.value;
1717
+ }
1718
+
1719
+ slide.opts.srcset = srcset;
1720
+ }
1721
+ }
1722
+
1723
+ // This will be wrapper containing both ghost and actual image
1724
+ slide.$content = $('<div class="fancybox-content"></div>')
1725
+ .addClass("fancybox-is-hidden")
1726
+ .appendTo(slide.$slide.addClass("fancybox-slide--image"));
1727
+
1728
+ // If we have a thumbnail, we can display it while actual image is loading
1729
+ // Users will not stare at black screen and actual image will appear gradually
1730
+ thumbSrc = slide.opts.thumb || (slide.opts.$thumb && slide.opts.$thumb.length ? slide.opts.$thumb.attr("src") : false);
1731
+
1732
+ if (slide.opts.preload !== false && slide.opts.width && slide.opts.height && thumbSrc) {
1733
+ slide.width = slide.opts.width;
1734
+ slide.height = slide.opts.height;
1735
+
1736
+ slide.$ghost = $("<img />")
1737
+ .one("error", function() {
1738
+ $(this).remove();
1739
+
1740
+ slide.$ghost = null;
1741
+ })
1742
+ .one("load", function() {
1743
+ self.afterLoad(slide);
1744
+ })
1745
+ .addClass("fancybox-image")
1746
+ .appendTo(slide.$content)
1747
+ .attr("src", thumbSrc);
1748
+ }
1749
+
1750
+ // Start loading actual image
1751
+ self.setBigImage(slide);
1752
+ },
1753
+
1754
+ // Create full-size image
1755
+ // ======================
1756
+
1757
+ setBigImage: function(slide) {
1758
+ var self = this,
1759
+ $img = $("<img />");
1760
+
1761
+ slide.$image = $img
1762
+ .one("error", function() {
1763
+ self.setError(slide);
1764
+ })
1765
+ .one("load", function() {
1766
+ var sizes;
1767
+
1768
+ if (!slide.$ghost) {
1769
+ self.resolveImageSlideSize(slide, this.naturalWidth, this.naturalHeight);
1770
+
1771
+ self.afterLoad(slide);
1772
+ }
1773
+
1774
+ // Clear timeout that checks if loading icon needs to be displayed
1775
+ if (slide.timouts) {
1776
+ clearTimeout(slide.timouts);
1777
+ slide.timouts = null;
1778
+ }
1779
+
1780
+ if (self.isClosing) {
1781
+ return;
1782
+ }
1783
+
1784
+ if (slide.opts.srcset) {
1785
+ sizes = slide.opts.sizes;
1786
+
1787
+ if (!sizes || sizes === "auto") {
1788
+ sizes =
1789
+ (slide.width / slide.height > 1 && $W.width() / $W.height() > 1 ? "100" : Math.round(slide.width / slide.height * 100)) +
1790
+ "vw";
1791
+ }
1792
+
1793
+ $img.attr("sizes", sizes).attr("srcset", slide.opts.srcset);
1794
+ }
1795
+
1796
+ // Hide temporary image after some delay
1797
+ if (slide.$ghost) {
1798
+ setTimeout(function() {
1799
+ if (slide.$ghost && !self.isClosing) {
1800
+ slide.$ghost.hide();
1801
+ }
1802
+ }, Math.min(300, Math.max(1000, slide.height / 1600)));
1803
+ }
1804
+
1805
+ self.hideLoading(slide);
1806
+ })
1807
+ .addClass("fancybox-image")
1808
+ .attr("src", slide.src)
1809
+ .appendTo(slide.$content);
1810
+
1811
+ if (($img[0].complete || $img[0].readyState == "complete") && $img[0].naturalWidth && $img[0].naturalHeight) {
1812
+ $img.trigger("load");
1813
+ } else if ($img[0].error) {
1814
+ $img.trigger("error");
1815
+ }
1816
+ },
1817
+
1818
+ // Computes the slide size from image size and maxWidth/maxHeight
1819
+ // ==============================================================
1820
+
1821
+ resolveImageSlideSize: function(slide, imgWidth, imgHeight) {
1822
+ var maxWidth = parseInt(slide.opts.width, 10),
1823
+ maxHeight = parseInt(slide.opts.height, 10);
1824
+
1825
+ // Sets the default values from the image
1826
+ slide.width = imgWidth;
1827
+ slide.height = imgHeight;
1828
+
1829
+ if (maxWidth > 0) {
1830
+ slide.width = maxWidth;
1831
+ slide.height = Math.floor(maxWidth * imgHeight / imgWidth);
1832
+ }
1833
+
1834
+ if (maxHeight > 0) {
1835
+ slide.width = Math.floor(maxHeight * imgWidth / imgHeight);
1836
+ slide.height = maxHeight;
1837
+ }
1838
+ },
1839
+
1840
+ // Create iframe wrapper, iframe and bindings
1841
+ // ==========================================
1842
+
1843
+ setIframe: function(slide) {
1844
+ var self = this,
1845
+ opts = slide.opts.iframe,
1846
+ $slide = slide.$slide,
1847
+ $iframe;
1848
+
1849
+ slide.$content = $('<div class="fancybox-content' + (opts.preload ? " fancybox-is-hidden" : "") + '"></div>')
1850
+ .css(opts.css)
1851
+ .appendTo($slide);
1852
+
1853
+ $slide.addClass("fancybox-slide--" + slide.contentType);
1854
+
1855
+ slide.$iframe = $iframe = $(opts.tpl.replace(/\{rnd\}/g, new Date().getTime()))
1856
+ .attr(opts.attr)
1857
+ .appendTo(slide.$content);
1858
+
1859
+ if (opts.preload) {
1860
+ self.showLoading(slide);
1861
+
1862
+ // Unfortunately, it is not always possible to determine if iframe is successfully loaded
1863
+ // (due to browser security policy)
1864
+
1865
+ $iframe.on("load.fb error.fb", function(e) {
1866
+ this.isReady = 1;
1867
+
1868
+ slide.$slide.trigger("refresh");
1869
+
1870
+ self.afterLoad(slide);
1871
+ });
1872
+
1873
+ // Recalculate iframe content size
1874
+ // ===============================
1875
+
1876
+ $slide.on("refresh.fb", function() {
1877
+ var $content = slide.$content,
1878
+ frameWidth = opts.css.width,
1879
+ frameHeight = opts.css.height,
1880
+ $contents,
1881
+ $body;
1882
+
1883
+ if ($iframe[0].isReady !== 1) {
1884
+ return;
1885
+ }
1886
+
1887
+ try {
1888
+ $contents = $iframe.contents();
1889
+ $body = $contents.find("body");
1890
+ } catch (ignore) {}
1891
+
1892
+ // Calculate contnet dimensions if it is accessible
1893
+ if ($body && $body.length && $body.children().length) {
1894
+ $content.css({
1895
+ width: "",
1896
+ height: ""
1897
+ });
1898
+
1899
+ if (frameWidth === undefined) {
1900
+ frameWidth = Math.ceil(Math.max($body[0].clientWidth, $body.outerWidth(true)));
1901
+ }
1902
+
1903
+ if (frameWidth) {
1904
+ $content.width(frameWidth);
1905
+ }
1906
+
1907
+ if (frameHeight === undefined) {
1908
+ frameHeight = Math.ceil(Math.max($body[0].clientHeight, $body.outerHeight(true)));
1909
+ }
1910
+
1911
+ if (frameHeight) {
1912
+ $content.height(frameHeight);
1913
+ }
1914
+ }
1915
+
1916
+ $content.removeClass("fancybox-is-hidden");
1917
+ });
1918
+ } else {
1919
+ this.afterLoad(slide);
1920
+ }
1921
+
1922
+ $iframe.attr("src", slide.src);
1923
+
1924
+ // Remove iframe if closing or changing gallery item
1925
+ $slide.one("onReset", function() {
1926
+ // This helps IE not to throw errors when closing
1927
+ try {
1928
+ $(this)
1929
+ .find("iframe")
1930
+ .hide()
1931
+ .unbind()
1932
+ .attr("src", "//about:blank");
1933
+ } catch (ignore) {}
1934
+
1935
+ $(this)
1936
+ .off("refresh.fb")
1937
+ .empty();
1938
+
1939
+ slide.isLoaded = false;
1940
+ });
1941
+ },
1942
+
1943
+ // Wrap and append content to the slide
1944
+ // ======================================
1945
+
1946
+ setContent: function(slide, content) {
1947
+ var self = this;
1948
+
1949
+ if (self.isClosing) {
1950
+ return;
1951
+ }
1952
+
1953
+ self.hideLoading(slide);
1954
+
1955
+ if (slide.$content) {
1956
+ $.fancybox.stop(slide.$content);
1957
+ }
1958
+
1959
+ slide.$slide.empty();
1960
+
1961
+ // If content is a jQuery object, then it will be moved to the slide.
1962
+ // The placeholder is created so we will know where to put it back.
1963
+ if (isQuery(content) && content.parent().length) {
1964
+ // Make sure content is not already moved to fancyBox
1965
+ content
1966
+ .parent()
1967
+ .parent(".fancybox-slide--inline")
1968
+ .trigger("onReset");
1969
+
1970
+ // Create temporary element marking original place of the content
1971
+ slide.$placeholder = $("<div>")
1972
+ .hide()
1973
+ .insertAfter(content);
1974
+
1975
+ // Make sure content is visible
1976
+ content.css("display", "inline-block");
1977
+ } else if (!slide.hasError) {
1978
+ // If content is just a plain text, try to convert it to html
1979
+ if ($.type(content) === "string") {
1980
+ content = $("<div>")
1981
+ .append($.trim(content))
1982
+ .contents();
1983
+
1984
+ // If we have text node, then add wrapping element to make vertical alignment work
1985
+ if (content[0].nodeType === 3) {
1986
+ content = $("<div>").html(content);
1987
+ }
1988
+ }
1989
+
1990
+ // If "filter" option is provided, then filter content
1991
+ if (slide.opts.filter) {
1992
+ content = $("<div>")
1993
+ .html(content)
1994
+ .find(slide.opts.filter);
1995
+ }
1996
+ }
1997
+
1998
+ slide.$slide.one("onReset", function() {
1999
+ // Pause all html5 video/audio
2000
+ $(this)
2001
+ .find("video,audio")
2002
+ .trigger("pause");
2003
+
2004
+ // Put content back
2005
+ if (slide.$placeholder) {
2006
+ slide.$placeholder.after(content.hide()).remove();
2007
+
2008
+ slide.$placeholder = null;
2009
+ }
2010
+
2011
+ // Remove custom close button
2012
+ if (slide.$smallBtn) {
2013
+ slide.$smallBtn.remove();
2014
+
2015
+ slide.$smallBtn = null;
2016
+ }
2017
+
2018
+ // Remove content and mark slide as not loaded
2019
+ if (!slide.hasError) {
2020
+ $(this).empty();
2021
+
2022
+ slide.isLoaded = false;
2023
+ }
2024
+ });
2025
+
2026
+ $(content).appendTo(slide.$slide);
2027
+
2028
+ if ($(content).is("video,audio")) {
2029
+ $(content).addClass("fancybox-video");
2030
+
2031
+ $(content).wrap("<div></div>");
2032
+
2033
+ slide.contentType = "video";
2034
+
2035
+ slide.opts.width = slide.opts.width || $(content).attr("width");
2036
+ slide.opts.height = slide.opts.height || $(content).attr("height");
2037
+ }
2038
+
2039
+ slide.$content = slide.$slide
2040
+ .children()
2041
+ .filter("div,form,main,video,audio")
2042
+ .first()
2043
+ .addClass("fancybox-content");
2044
+
2045
+ slide.$slide.addClass("fancybox-slide--" + slide.contentType);
2046
+
2047
+ this.afterLoad(slide);
2048
+ },
2049
+
2050
+ // Display error message
2051
+ // =====================
2052
+
2053
+ setError: function(slide) {
2054
+ slide.hasError = true;
2055
+
2056
+ slide.$slide
2057
+ .trigger("onReset")
2058
+ .removeClass("fancybox-slide--" + slide.contentType)
2059
+ .addClass("fancybox-slide--error");
2060
+
2061
+ slide.contentType = "html";
2062
+
2063
+ this.setContent(slide, this.translate(slide, slide.opts.errorTpl));
2064
+
2065
+ if (slide.pos === this.currPos) {
2066
+ this.isAnimating = false;
2067
+ }
2068
+ },
2069
+
2070
+ // Show loading icon inside the slide
2071
+ // ==================================
2072
+
2073
+ showLoading: function(slide) {
2074
+ var self = this;
2075
+
2076
+ slide = slide || self.current;
2077
+
2078
+ if (slide && !slide.$spinner) {
2079
+ slide.$spinner = $(self.translate(self, self.opts.spinnerTpl)).appendTo(slide.$slide);
2080
+ }
2081
+ },
2082
+
2083
+ // Remove loading icon from the slide
2084
+ // ==================================
2085
+
2086
+ hideLoading: function(slide) {
2087
+ var self = this;
2088
+
2089
+ slide = slide || self.current;
2090
+
2091
+ if (slide && slide.$spinner) {
2092
+ slide.$spinner.remove();
2093
+
2094
+ delete slide.$spinner;
2095
+ }
2096
+ },
2097
+
2098
+ // Adjustments after slide content has been loaded
2099
+ // ===============================================
2100
+
2101
+ afterLoad: function(slide) {
2102
+ var self = this;
2103
+
2104
+ if (self.isClosing) {
2105
+ return;
2106
+ }
2107
+
2108
+ slide.isLoading = false;
2109
+ slide.isLoaded = true;
2110
+
2111
+ self.trigger("afterLoad", slide);
2112
+
2113
+ self.hideLoading(slide);
2114
+
2115
+ if (slide.pos === self.currPos) {
2116
+ self.updateCursor();
2117
+ }
2118
+
2119
+ if (slide.opts.smallBtn && (!slide.$smallBtn || !slide.$smallBtn.length)) {
2120
+ slide.$smallBtn = $(self.translate(slide, slide.opts.btnTpl.smallBtn)).prependTo(slide.$content);
2121
+ }
2122
+
2123
+ if (slide.opts.protect && slide.$content && !slide.hasError) {
2124
+ // Disable right click
2125
+ slide.$content.on("contextmenu.fb", function(e) {
2126
+ if (e.button == 2) {
2127
+ e.preventDefault();
2128
+ }
2129
+
2130
+ return true;
2131
+ });
2132
+
2133
+ // Add fake element on top of the image
2134
+ // This makes a bit harder for user to select image
2135
+ if (slide.type === "image") {
2136
+ $('<div class="fancybox-spaceball"></div>').appendTo(slide.$content);
2137
+ }
2138
+ }
2139
+
2140
+ self.revealContent(slide);
2141
+ },
2142
+
2143
+ // Make content visible
2144
+ // This method is called right after content has been loaded or
2145
+ // user navigates gallery and transition should start
2146
+ // ============================================================
2147
+
2148
+ revealContent: function(slide) {
2149
+ var self = this,
2150
+ $slide = slide.$slide,
2151
+ end = false,
2152
+ start = false,
2153
+ effect,
2154
+ effectClassName,
2155
+ duration,
2156
+ opacity;
2157
+
2158
+ effect = slide.opts[self.firstRun ? "animationEffect" : "transitionEffect"];
2159
+ duration = slide.opts[self.firstRun ? "animationDuration" : "transitionDuration"];
2160
+
2161
+ duration = parseInt(slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10);
2162
+
2163
+ // Do not animate if revealing the same slide
2164
+ if (slide.pos === self.currPos) {
2165
+ if (slide.isComplete) {
2166
+ effect = false;
2167
+ } else {
2168
+ self.isAnimating = true;
2169
+ }
2170
+ }
2171
+
2172
+ if (slide.isMoved || slide.pos !== self.currPos || !duration) {
2173
+ effect = false;
2174
+ }
2175
+
2176
+ // Check if can zoom
2177
+ if (effect === "zoom") {
2178
+ if (slide.pos === self.currPos && duration && slide.type === "image" && !slide.hasError && (start = self.getThumbPos(slide))) {
2179
+ end = self.getFitPos(slide);
2180
+ } else {
2181
+ effect = "fade";
2182
+ }
2183
+ }
2184
+
2185
+ // Zoom animation
2186
+ // ==============
2187
+ if (effect === "zoom") {
2188
+ end.scaleX = end.width / start.width;
2189
+ end.scaleY = end.height / start.height;
2190
+
2191
+ // Check if we need to animate opacity
2192
+ opacity = slide.opts.zoomOpacity;
2193
+
2194
+ if (opacity == "auto") {
2195
+ opacity = Math.abs(slide.width / slide.height - start.width / start.height) > 0.1;
2196
+ }
2197
+
2198
+ if (opacity) {
2199
+ start.opacity = 0.1;
2200
+ end.opacity = 1;
2201
+ }
2202
+
2203
+ // Draw image at start position
2204
+ $.fancybox.setTranslate(slide.$content.removeClass("fancybox-is-hidden"), start);
2205
+
2206
+ forceRedraw(slide.$content);
2207
+
2208
+ // Start animation
2209
+ $.fancybox.animate(slide.$content, end, duration, function() {
2210
+ self.isAnimating = false;
2211
+
2212
+ self.complete();
2213
+ });
2214
+
2215
+ return;
2216
+ }
2217
+
2218
+ self.updateSlide(slide);
2219
+
2220
+ // Simply show content
2221
+ // ===================
2222
+
2223
+ if (!effect) {
2224
+ forceRedraw($slide);
2225
+
2226
+ slide.$content.removeClass("fancybox-is-hidden");
2227
+
2228
+ if (slide.pos === self.currPos) {
2229
+ self.complete();
2230
+ }
2231
+
2232
+ return;
2233
+ }
2234
+
2235
+ $.fancybox.stop($slide);
2236
+
2237
+ effectClassName = "fancybox-animated fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-fx-" + effect;
2238
+
2239
+ $slide
2240
+ .removeAttr("style")
2241
+ .removeClass("fancybox-slide--current fancybox-slide--next fancybox-slide--previous")
2242
+ .addClass(effectClassName);
2243
+
2244
+ slide.$content.removeClass("fancybox-is-hidden");
2245
+
2246
+ // Force reflow for CSS3 transitions
2247
+ forceRedraw($slide);
2248
+
2249
+ $.fancybox.animate(
2250
+ $slide,
2251
+ "fancybox-slide--current",
2252
+ duration,
2253
+ function(e) {
2254
+ $slide.removeClass(effectClassName).removeAttr("style");
2255
+
2256
+ if (slide.pos === self.currPos) {
2257
+ self.complete();
2258
+ }
2259
+ },
2260
+ true
2261
+ );
2262
+ },
2263
+
2264
+ // Check if we can and have to zoom from thumbnail
2265
+ //================================================
2266
+
2267
+ getThumbPos: function(slide) {
2268
+ var self = this,
2269
+ rez = false,
2270
+ $thumb = slide.opts.$thumb,
2271
+ thumbPos = $thumb && $thumb.length && $thumb[0].ownerDocument === document ? $thumb.offset() : 0,
2272
+ slidePos;
2273
+
2274
+ // Check if element is inside the viewport by at least 1 pixel
2275
+ var isElementVisible = function($el) {
2276
+ var element = $el[0],
2277
+ elementRect = element.getBoundingClientRect(),
2278
+ parentRects = [],
2279
+ visibleInAllParents;
2280
+
2281
+ while (element.parentElement !== null) {
2282
+ if ($(element.parentElement).css("overflow") === "hidden" || $(element.parentElement).css("overflow") === "auto") {
2283
+ parentRects.push(element.parentElement.getBoundingClientRect());
2284
+ }
2285
+
2286
+ element = element.parentElement;
2287
+ }
2288
+
2289
+ visibleInAllParents = parentRects.every(function(parentRect) {
2290
+ var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
2291
+ var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
2292
+
2293
+ return visiblePixelX > 0 && visiblePixelY > 0;
2294
+ });
2295
+
2296
+ return (
2297
+ visibleInAllParents &&
2298
+ elementRect.bottom > 0 &&
2299
+ elementRect.right > 0 &&
2300
+ elementRect.left < $(window).width() &&
2301
+ elementRect.top < $(window).height()
2302
+ );
2303
+ };
2304
+
2305
+ if (thumbPos && isElementVisible($thumb)) {
2306
+ slidePos = self.$refs.stage.offset();
2307
+
2308
+ rez = {
2309
+ top: thumbPos.top - slidePos.top + parseFloat($thumb.css("border-top-width") || 0),
2310
+ left: thumbPos.left - slidePos.left + parseFloat($thumb.css("border-left-width") || 0),
2311
+ width: $thumb.width(),
2312
+ height: $thumb.height(),
2313
+ scaleX: 1,
2314
+ scaleY: 1
2315
+ };
2316
+ }
2317
+
2318
+ return rez;
2319
+ },
2320
+
2321
+ // Final adjustments after current gallery item is moved to position
2322
+ // and it`s content is loaded
2323
+ // ==================================================================
2324
+
2325
+ complete: function() {
2326
+ var self = this,
2327
+ current = self.current,
2328
+ slides = {};
2329
+
2330
+ if (current.isMoved || !current.isLoaded) {
2331
+ return;
2332
+ }
2333
+
2334
+ if (!current.isComplete) {
2335
+ current.isComplete = true;
2336
+
2337
+ current.$slide.siblings().trigger("onReset");
2338
+
2339
+ self.preload("inline");
2340
+
2341
+ // Trigger any CSS3 transiton inside the slide
2342
+ forceRedraw(current.$slide);
2343
+
2344
+ current.$slide.addClass("fancybox-slide--complete");
2345
+
2346
+ // Remove unnecessary slides
2347
+ $.each(self.slides, function(key, slide) {
2348
+ if (slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1) {
2349
+ slides[slide.pos] = slide;
2350
+ } else if (slide) {
2351
+ $.fancybox.stop(slide.$slide);
2352
+
2353
+ slide.$slide.off().remove();
2354
+ }
2355
+ });
2356
+
2357
+ self.slides = slides;
2358
+ }
2359
+
2360
+ self.isAnimating = false;
2361
+
2362
+ self.updateCursor();
2363
+
2364
+ self.trigger("afterShow");
2365
+
2366
+ // Play first html5 video/audio
2367
+ current.$slide
2368
+ .find("video,audio")
2369
+ .filter(":visible:first")
2370
+ .trigger("play");
2371
+
2372
+ // Try to focus on the first focusable element
2373
+ if (
2374
+ $(document.activeElement).is("[disabled]") ||
2375
+ (current.opts.autoFocus && !(current.type == "image" || current.type === "iframe"))
2376
+ ) {
2377
+ self.focus();
2378
+ }
2379
+ },
2380
+
2381
+ // Preload next and previous slides
2382
+ // ================================
2383
+
2384
+ preload: function(type) {
2385
+ var self = this,
2386
+ next = self.slides[self.currPos + 1],
2387
+ prev = self.slides[self.currPos - 1];
2388
+
2389
+ if (next && next.type === type) {
2390
+ self.loadSlide(next);
2391
+ }
2392
+
2393
+ if (prev && prev.type === type) {
2394
+ self.loadSlide(prev);
2395
+ }
2396
+ },
2397
+
2398
+ // Try to find and focus on the first focusable element
2399
+ // ====================================================
2400
+
2401
+ focus: function() {
2402
+ var current = this.current,
2403
+ $el;
2404
+
2405
+ if (this.isClosing) {
2406
+ return;
2407
+ }
2408
+
2409
+ if (current && current.isComplete && current.$content) {
2410
+ // Look for first input with autofocus attribute
2411
+ $el = current.$content.find("input[autofocus]:enabled:visible:first");
2412
+
2413
+ if (!$el.length) {
2414
+ $el = current.$content.find("button,:input,[tabindex],a").filter(":enabled:visible:first");
2415
+ }
2416
+
2417
+ $el = $el && $el.length ? $el : current.$content;
2418
+
2419
+ $el.trigger("focus");
2420
+ }
2421
+ },
2422
+
2423
+ // Activates current instance - brings container to the front and enables keyboard,
2424
+ // notifies other instances about deactivating
2425
+ // =================================================================================
2426
+
2427
+ activate: function() {
2428
+ var self = this;
2429
+
2430
+ // Deactivate all instances
2431
+ $(".fancybox-container").each(function() {
2432
+ var instance = $(this).data("FancyBox");
2433
+
2434
+ // Skip self and closing instances
2435
+ if (instance && instance.id !== self.id && !instance.isClosing) {
2436
+ instance.trigger("onDeactivate");
2437
+
2438
+ instance.removeEvents();
2439
+
2440
+ instance.isVisible = false;
2441
+ }
2442
+ });
2443
+
2444
+ self.isVisible = true;
2445
+
2446
+ if (self.current || self.isIdle) {
2447
+ self.update();
2448
+
2449
+ self.updateControls();
2450
+ }
2451
+
2452
+ self.trigger("onActivate");
2453
+
2454
+ self.addEvents();
2455
+ },
2456
+
2457
+ // Start closing procedure
2458
+ // This will start "zoom-out" animation if needed and clean everything up afterwards
2459
+ // =================================================================================
2460
+
2461
+ close: function(e, d) {
2462
+ var self = this,
2463
+ current = self.current,
2464
+ effect,
2465
+ duration,
2466
+ $content,
2467
+ domRect,
2468
+ opacity,
2469
+ start,
2470
+ end;
2471
+
2472
+ var done = function() {
2473
+ self.cleanUp(e);
2474
+ };
2475
+
2476
+ if (self.isClosing) {
2477
+ return false;
2478
+ }
2479
+
2480
+ self.isClosing = true;
2481
+
2482
+ // If beforeClose callback prevents closing, make sure content is centered
2483
+ if (self.trigger("beforeClose", e) === false) {
2484
+ self.isClosing = false;
2485
+
2486
+ requestAFrame(function() {
2487
+ self.update();
2488
+ });
2489
+
2490
+ return false;
2491
+ }
2492
+
2493
+ // Remove all events
2494
+ // If there are multiple instances, they will be set again by "activate" method
2495
+ self.removeEvents();
2496
+
2497
+ if (current.timouts) {
2498
+ clearTimeout(current.timouts);
2499
+ }
2500
+
2501
+ $content = current.$content;
2502
+ effect = current.opts.animationEffect;
2503
+ duration = $.isNumeric(d) ? d : effect ? current.opts.animationDuration : 0;
2504
+
2505
+ // Remove other slides
2506
+ current.$slide
2507
+ .off(transitionEnd)
2508
+ .removeClass("fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated");
2509
+
2510
+ current.$slide
2511
+ .siblings()
2512
+ .trigger("onReset")
2513
+ .remove();
2514
+
2515
+ // Trigger animations
2516
+ if (duration) {
2517
+ self.$refs.container.removeClass("fancybox-is-open").addClass("fancybox-is-closing");
2518
+ }
2519
+
2520
+ // Clean up
2521
+ self.hideLoading(current);
2522
+
2523
+ self.hideControls();
2524
+
2525
+ self.updateCursor();
2526
+
2527
+ // Check if possible to zoom-out
2528
+ if (
2529
+ effect === "zoom" &&
2530
+ !(e !== true && $content && duration && current.type === "image" && !current.hasError && (end = self.getThumbPos(current)))
2531
+ ) {
2532
+ effect = "fade";
2533
+ }
2534
+
2535
+ if (effect === "zoom") {
2536
+ $.fancybox.stop($content);
2537
+
2538
+ domRect = $.fancybox.getTranslate($content);
2539
+
2540
+ start = {
2541
+ top: domRect.top,
2542
+ left: domRect.left,
2543
+ scaleX: domRect.width / end.width,
2544
+ scaleY: domRect.height / end.height,
2545
+ width: end.width,
2546
+ height: end.height
2547
+ };
2548
+
2549
+ // Check if we need to animate opacity
2550
+ opacity = current.opts.zoomOpacity;
2551
+
2552
+ if (opacity == "auto") {
2553
+ opacity = Math.abs(current.width / current.height - end.width / end.height) > 0.1;
2554
+ }
2555
+
2556
+ if (opacity) {
2557
+ end.opacity = 0;
2558
+ }
2559
+
2560
+ $.fancybox.setTranslate($content, start);
2561
+
2562
+ forceRedraw($content);
2563
+
2564
+ $.fancybox.animate($content, end, duration, done);
2565
+
2566
+ return true;
2567
+ }
2568
+
2569
+ if (effect && duration) {
2570
+ // If skip animation
2571
+ if (e === true) {
2572
+ setTimeout(done, duration);
2573
+ } else {
2574
+ $.fancybox.animate(
2575
+ current.$slide.removeClass("fancybox-slide--current"),
2576
+ "fancybox-animated fancybox-slide--previous fancybox-fx-" + effect,
2577
+ duration,
2578
+ done
2579
+ );
2580
+ }
2581
+ } else {
2582
+ done();
2583
+ }
2584
+
2585
+ return true;
2586
+ },
2587
+
2588
+ // Final adjustments after removing the instance
2589
+ // =============================================
2590
+
2591
+ cleanUp: function(e) {
2592
+ var self = this,
2593
+ $body = $("body"),
2594
+ instance,
2595
+ scrollTop;
2596
+
2597
+ self.current.$slide.trigger("onReset");
2598
+
2599
+ self.$refs.container.empty().remove();
2600
+
2601
+ self.trigger("afterClose", e);
2602
+
2603
+ // Place back focus
2604
+ if (self.$lastFocus && !!self.current.opts.backFocus) {
2605
+ self.$lastFocus.trigger("focus");
2606
+ }
2607
+
2608
+ self.current = null;
2609
+
2610
+ // Check if there are other instances
2611
+ instance = $.fancybox.getInstance();
2612
+
2613
+ if (instance) {
2614
+ instance.activate();
2615
+ } else {
2616
+ $body.removeClass("fancybox-active compensate-for-scrollbar");
2617
+
2618
+ $("#fancybox-style-noscroll").remove();
2619
+ }
2620
+ },
2621
+
2622
+ // Call callback and trigger an event
2623
+ // ==================================
2624
+
2625
+ trigger: function(name, slide) {
2626
+ var args = Array.prototype.slice.call(arguments, 1),
2627
+ self = this,
2628
+ obj = slide && slide.opts ? slide : self.current,
2629
+ rez;
2630
+
2631
+ if (obj) {
2632
+ args.unshift(obj);
2633
+ } else {
2634
+ obj = self;
2635
+ }
2636
+
2637
+ args.unshift(self);
2638
+
2639
+ if ($.isFunction(obj.opts[name])) {
2640
+ rez = obj.opts[name].apply(obj, args);
2641
+ }
2642
+
2643
+ if (rez === false) {
2644
+ return rez;
2645
+ }
2646
+
2647
+ if (name === "afterClose" || !self.$refs) {
2648
+ $D.trigger(name + ".fb", args);
2649
+ } else {
2650
+ self.$refs.container.trigger(name + ".fb", args);
2651
+ }
2652
+ },
2653
+
2654
+ // Update infobar values, navigation button states and reveal caption
2655
+ // ==================================================================
2656
+
2657
+ updateControls: function(force) {
2658
+ var self = this,
2659
+ current = self.current,
2660
+ index = current.index,
2661
+ caption = current.opts.caption,
2662
+ $container = self.$refs.container,
2663
+ $caption = self.$refs.caption;
2664
+
2665
+ // Recalculate content dimensions
2666
+ current.$slide.trigger("refresh");
2667
+
2668
+ self.$caption = caption && caption.length ? $caption.html(caption) : null;
2669
+
2670
+ if (!self.isHiddenControls && !self.isIdle) {
2671
+ self.showControls();
2672
+ }
2673
+
2674
+ // Update info and navigation elements
2675
+ $container.find("[data-fancybox-count]").html(self.group.length);
2676
+ $container.find("[data-fancybox-index]").html(index + 1);
2677
+
2678
+ $container.find("[data-fancybox-prev]").toggleClass("disabled", !current.opts.loop && index <= 0);
2679
+ $container.find("[data-fancybox-next]").toggleClass("disabled", !current.opts.loop && index >= self.group.length - 1);
2680
+
2681
+ if (current.type === "image") {
2682
+ // Re-enable buttons; update download button source
2683
+ $container
2684
+ .find("[data-fancybox-zoom]")
2685
+ .show()
2686
+ .end()
2687
+ .find("[data-fancybox-download]")
2688
+ .attr("href", current.opts.image.src || current.src)
2689
+ .show();
2690
+ } else if (current.opts.toolbar) {
2691
+ $container.find("[data-fancybox-download],[data-fancybox-zoom]").hide();
2692
+ }
2693
+ },
2694
+
2695
+ // Hide toolbar and caption
2696
+ // ========================
2697
+
2698
+ hideControls: function() {
2699
+ this.isHiddenControls = true;
2700
+
2701
+ this.$refs.container.removeClass("fancybox-show-infobar fancybox-show-toolbar fancybox-show-caption fancybox-show-nav");
2702
+ },
2703
+
2704
+ showControls: function() {
2705
+ var self = this,
2706
+ opts = self.current ? self.current.opts : self.opts,
2707
+ $container = self.$refs.container;
2708
+
2709
+ self.isHiddenControls = false;
2710
+ self.idleSecondsCounter = 0;
2711
+
2712
+ $container
2713
+ .toggleClass("fancybox-show-toolbar", !!(opts.toolbar && opts.buttons))
2714
+ .toggleClass("fancybox-show-infobar", !!(opts.infobar && self.group.length > 1))
2715
+ .toggleClass("fancybox-show-nav", !!(opts.arrows && self.group.length > 1))
2716
+ .toggleClass("fancybox-is-modal", !!opts.modal);
2717
+
2718
+ if (self.$caption) {
2719
+ $container.addClass("fancybox-show-caption ");
2720
+ } else {
2721
+ $container.removeClass("fancybox-show-caption");
2722
+ }
2723
+ },
2724
+
2725
+ // Toggle toolbar and caption
2726
+ // ==========================
2727
+
2728
+ toggleControls: function() {
2729
+ if (this.isHiddenControls) {
2730
+ this.showControls();
2731
+ } else {
2732
+ this.hideControls();
2733
+ }
2734
+ }
2735
+ });
2736
+
2737
+ $.fancybox = {
2738
+ version: "{fancybox-version}",
2739
+ defaults: defaults,
2740
+
2741
+ // Get current instance and execute a command.
2742
+ //
2743
+ // Examples of usage:
2744
+ //
2745
+ // $instance = $.fancybox.getInstance();
2746
+ // $.fancybox.getInstance().jumpTo( 1 );
2747
+ // $.fancybox.getInstance( 'jumpTo', 1 );
2748
+ // $.fancybox.getInstance( function() {
2749
+ // console.info( this.currIndex );
2750
+ // });
2751
+ // ======================================================
2752
+
2753
+ getInstance: function(command) {
2754
+ var instance = $('.fancybox-container:not(".fancybox-is-closing"):last').data("FancyBox"),
2755
+ args = Array.prototype.slice.call(arguments, 1);
2756
+
2757
+ if (instance instanceof FancyBox) {
2758
+ if ($.type(command) === "string") {
2759
+ instance[command].apply(instance, args);
2760
+ } else if ($.type(command) === "function") {
2761
+ command.apply(instance, args);
2762
+ }
2763
+
2764
+ return instance;
2765
+ }
2766
+
2767
+ return false;
2768
+ },
2769
+
2770
+ // Create new instance
2771
+ // ===================
2772
+
2773
+ open: function(items, opts, index) {
2774
+ return new FancyBox(items, opts, index);
2775
+ },
2776
+
2777
+ // Close current or all instances
2778
+ // ==============================
2779
+
2780
+ close: function(all) {
2781
+ var instance = this.getInstance();
2782
+
2783
+ if (instance) {
2784
+ instance.close();
2785
+
2786
+ // Try to find and close next instance
2787
+
2788
+ if (all === true) {
2789
+ this.close();
2790
+ }
2791
+ }
2792
+ },
2793
+
2794
+ // Close all instances and unbind all events
2795
+ // =========================================
2796
+
2797
+ destroy: function() {
2798
+ this.close(true);
2799
+
2800
+ $D.add("body").off("click.fb-start", "**");
2801
+ },
2802
+
2803
+ // Try to detect mobile devices
2804
+ // ============================
2805
+
2806
+ isMobile:
2807
+ document.createTouch !== undefined && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
2808
+
2809
+ // Detect if 'translate3d' support is available
2810
+ // ============================================
2811
+
2812
+ use3d: (function() {
2813
+ var div = document.createElement("div");
2814
+
2815
+ return (
2816
+ window.getComputedStyle &&
2817
+ window.getComputedStyle(div) &&
2818
+ window.getComputedStyle(div).getPropertyValue("transform") &&
2819
+ !(document.documentMode && document.documentMode < 11)
2820
+ );
2821
+ })(),
2822
+
2823
+ // Helper function to get current visual state of an element
2824
+ // returns array[ top, left, horizontal-scale, vertical-scale, opacity ]
2825
+ // =====================================================================
2826
+
2827
+ getTranslate: function($el) {
2828
+ var domRect;
2829
+
2830
+ if (!$el || !$el.length) {
2831
+ return false;
2832
+ }
2833
+
2834
+ domRect = $el[0].getBoundingClientRect();
2835
+
2836
+ return {
2837
+ top: domRect.top || 0,
2838
+ left: domRect.left || 0,
2839
+ width: domRect.width,
2840
+ height: domRect.height,
2841
+ opacity: parseFloat($el.css("opacity"))
2842
+ };
2843
+ },
2844
+
2845
+ // Shortcut for setting "translate3d" properties for element
2846
+ // Can set be used to set opacity, too
2847
+ // ========================================================
2848
+
2849
+ setTranslate: function($el, props) {
2850
+ var str = "",
2851
+ css = {};
2852
+
2853
+ if (!$el || !props) {
2854
+ return;
2855
+ }
2856
+
2857
+ if (props.left !== undefined || props.top !== undefined) {
2858
+ str =
2859
+ (props.left === undefined ? $el.position().left : props.left) +
2860
+ "px, " +
2861
+ (props.top === undefined ? $el.position().top : props.top) +
2862
+ "px";
2863
+
2864
+ if (this.use3d) {
2865
+ str = "translate3d(" + str + ", 0px)";
2866
+ } else {
2867
+ str = "translate(" + str + ")";
2868
+ }
2869
+ }
2870
+
2871
+ if (props.scaleX !== undefined && props.scaleY !== undefined) {
2872
+ str = (str.length ? str + " " : "") + "scale(" + props.scaleX + ", " + props.scaleY + ")";
2873
+ }
2874
+
2875
+ if (str.length) {
2876
+ css.transform = str;
2877
+ }
2878
+
2879
+ if (props.opacity !== undefined) {
2880
+ css.opacity = props.opacity;
2881
+ }
2882
+
2883
+ if (props.width !== undefined) {
2884
+ css.width = props.width;
2885
+ }
2886
+
2887
+ if (props.height !== undefined) {
2888
+ css.height = props.height;
2889
+ }
2890
+
2891
+ return $el.css(css);
2892
+ },
2893
+
2894
+ // Simple CSS transition handler
2895
+ // =============================
2896
+
2897
+ animate: function($el, to, duration, callback, leaveAnimationName) {
2898
+ var final = false;
2899
+
2900
+ if ($.isFunction(duration)) {
2901
+ callback = duration;
2902
+ duration = null;
2903
+ }
2904
+
2905
+ if (!$.isPlainObject(to)) {
2906
+ $el.removeAttr("style");
2907
+ }
2908
+
2909
+ $.fancybox.stop($el);
2910
+
2911
+ $el.on(transitionEnd, function(e) {
2912
+ // Skip events from child elements and z-index change
2913
+ if (e && e.originalEvent && (!$el.is(e.originalEvent.target) || e.originalEvent.propertyName == "z-index")) {
2914
+ return;
2915
+ }
2916
+
2917
+ $.fancybox.stop($el);
2918
+
2919
+ if (final) {
2920
+ $.fancybox.setTranslate($el, final);
2921
+ }
2922
+
2923
+ if ($.isPlainObject(to)) {
2924
+ if (leaveAnimationName === false) {
2925
+ $el.removeAttr("style");
2926
+ }
2927
+ } else if (leaveAnimationName !== true) {
2928
+ $el.removeClass(to);
2929
+ }
2930
+
2931
+ if ($.isFunction(callback)) {
2932
+ callback(e);
2933
+ }
2934
+ });
2935
+
2936
+ if ($.isNumeric(duration)) {
2937
+ $el.css("transition-duration", duration + "ms");
2938
+ }
2939
+
2940
+ // Start animation by changing CSS properties or class name
2941
+ if ($.isPlainObject(to)) {
2942
+ if (to.scaleX !== undefined && to.scaleY !== undefined) {
2943
+ final = $.extend({}, to, {
2944
+ width: $el.width() * to.scaleX,
2945
+ height: $el.height() * to.scaleY,
2946
+ scaleX: 1,
2947
+ scaleY: 1
2948
+ });
2949
+
2950
+ delete to.width;
2951
+ delete to.height;
2952
+
2953
+ if ($el.parent().hasClass("fancybox-slide--image")) {
2954
+ $el.parent().addClass("fancybox-is-scaling");
2955
+ }
2956
+ }
2957
+
2958
+ $.fancybox.setTranslate($el, to);
2959
+ } else {
2960
+ $el.addClass(to);
2961
+ }
2962
+
2963
+ // Make sure that `transitionend` callback gets fired
2964
+ $el.data(
2965
+ "timer",
2966
+ setTimeout(function() {
2967
+ $el.trigger("transitionend");
2968
+ }, duration + 16)
2969
+ );
2970
+ },
2971
+
2972
+ stop: function($el) {
2973
+ if ($el && $el.length) {
2974
+ clearTimeout($el.data("timer"));
2975
+
2976
+ $el.off("transitionend").css("transition-duration", "");
2977
+
2978
+ $el.parent().removeClass("fancybox-is-scaling");
2979
+ }
2980
+ }
2981
+ };
2982
+
2983
+ // Default click handler for "fancyboxed" links
2984
+ // ============================================
2985
+
2986
+ function _run(e, opts) {
2987
+ var items = [],
2988
+ index = 0,
2989
+ $target,
2990
+ value;
2991
+
2992
+ // Avoid opening multiple times
2993
+ if (e && e.isDefaultPrevented()) {
2994
+ return;
2995
+ }
2996
+
2997
+ e.preventDefault();
2998
+
2999
+ opts = e && e.data ? e.data.options : opts || {};
3000
+
3001
+ $target = opts.$target || $(e.currentTarget);
3002
+ value = $target.attr("data-fancybox") || "";
3003
+
3004
+ // Get all related items and find index for clicked one
3005
+ if (value) {
3006
+ items = opts.selector ? $(opts.selector) : e.data ? e.data.items : [];
3007
+ items = items.length ? items.filter('[data-fancybox="' + value + '"]') : $('[data-fancybox="' + value + '"]');
3008
+
3009
+ index = items.index($target);
3010
+
3011
+ // Sometimes current item can not be found (for example, if some script clones items)
3012
+ if (index < 0) {
3013
+ index = 0;
3014
+ }
3015
+ } else {
3016
+ items = [$target];
3017
+ }
3018
+
3019
+ $.fancybox.open(items, opts, index);
3020
+ }
3021
+
3022
+ // Create a jQuery plugin
3023
+ // ======================
3024
+
3025
+ $.fn.fancybox = function(options) {
3026
+ var selector;
3027
+
3028
+ options = options || {};
3029
+ selector = options.selector || false;
3030
+
3031
+ if (selector) {
3032
+ // Use body element instead of document so it executes first
3033
+ $("body")
3034
+ .off("click.fb-start", selector)
3035
+ .on("click.fb-start", selector, {options: options}, _run);
3036
+ } else {
3037
+ this.off("click.fb-start").on(
3038
+ "click.fb-start",
3039
+ {
3040
+ items: this,
3041
+ options: options
3042
+ },
3043
+ _run
3044
+ );
3045
+ }
3046
+
3047
+ return this;
3048
+ };
3049
+
3050
+ // Self initializing plugin for all elements having `data-fancybox` attribute
3051
+ // ==========================================================================
3052
+
3053
+ $D.on("click.fb-start", "[data-fancybox]", _run);
3054
+
3055
+ // Enable "trigger elements"
3056
+ // =========================
3057
+
3058
+ $D.on("click.fb-start", "[data-trigger]", function(e) {
3059
+ _run(e, {
3060
+ $target: $('[data-fancybox="' + $(e.currentTarget).attr("data-trigger") + '"]').eq($(e.currentTarget).attr("data-index") || 0),
3061
+ $trigger: $(this)
3062
+ });
3063
+ });
3064
+ })(window, document, window.jQuery || jQuery);