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