Subversion-Projekte lars-tiefland.ci

Revision

Revision 47 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
41 lars 1
/*!
2
 * fancyBox - jQuery Plugin
3
 * version: 2.1.5 (Fri, 14 Jun 2013)
4
 * @requires jQuery v1.6 or later
5
 *
6
 * Examples at http://fancyapps.com/fancybox/
7
 * License: www.fancyapps.com/fancybox/#license
8
 *
9
 * Copyright 2012 Janis Skarnelis - janis@fancyapps.com
10
 *
11
 */
12
 
13
(function (window, document, $, undefined) {
14
	"use strict";
15
 
16
	var H = $("html"),
17
		W = $(window),
18
		D = $(document),
19
		F = $.fancybox = function () {
20
			F.open.apply( this, arguments );
21
		},
22
		IE =  navigator.userAgent.match(/msie/i),
23
		didUpdate	= null,
24
		isTouch		= document.createTouch !== undefined,
25
 
26
		isQuery	= function(obj) {
27
			return obj && obj.hasOwnProperty && obj instanceof $;
28
		},
29
		isString = function(str) {
30
			return str && $.type(str) === "string";
31
		},
32
		isPercentage = function(str) {
33
			return isString(str) && str.indexOf('%') > 0;
34
		},
35
		isScrollable = function(el) {
36
			return (el && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight)));
37
		},
38
		getScalar = function(orig, dim) {
39
			var value = parseInt(orig, 10) || 0;
40
 
41
			if (dim && isPercentage(orig)) {
42
				value = F.getViewport()[ dim ] / 100 * value;
43
			}
44
 
45
			return Math.ceil(value);
46
		},
47
		getValue = function(value, dim) {
48
			return getScalar(value, dim) + 'px';
49
		};
50
 
51
	$.extend(F, {
52
		// The current version of fancyBox
53
		version: '2.1.5',
54
 
55
		defaults: {
56
			padding : 15,
57
			margin  : 20,
58
 
59
			width     : 800,
60
			height    : 600,
61
			minWidth  : 100,
62
			minHeight : 100,
63
			maxWidth  : 9999,
64
			maxHeight : 9999,
65
			pixelRatio: 1, // Set to 2 for retina display support
66
 
67
			autoSize   : true,
68
			autoHeight : false,
69
			autoWidth  : false,
70
 
71
			autoResize  : true,
72
			autoCenter  : !isTouch,
73
			fitToView   : true,
74
			aspectRatio : false,
75
			topRatio    : 0.5,
76
			leftRatio   : 0.5,
77
 
78
			scrolling : 'auto', // 'auto', 'yes' or 'no'
79
			wrapCSS   : '',
80
 
81
			arrows     : true,
82
			closeBtn   : true,
83
			closeClick : false,
84
			nextClick  : false,
85
			mouseWheel : true,
86
			autoPlay   : false,
87
			playSpeed  : 3000,
88
			preload    : 3,
89
			modal      : false,
90
			loop       : true,
91
 
92
			ajax  : {
93
				dataType : 'html',
94
				headers  : { 'X-fancyBox': true }
95
			},
96
			iframe : {
97
				scrolling : 'auto',
98
				preload   : true
99
			},
100
			swf : {
101
				wmode: 'transparent',
102
				allowfullscreen   : 'true',
103
				allowscriptaccess : 'always'
104
			},
105
 
106
			keys  : {
107
				next : {
108
					13 : 'left', // enter
109
					34 : 'up',   // page down
110
					39 : 'left', // right arrow
111
					40 : 'up'    // down arrow
112
				},
113
				prev : {
114
					8  : 'right',  // backspace
115
					33 : 'down',   // page up
116
					37 : 'right',  // left arrow
117
					38 : 'down'    // up arrow
118
				},
119
				close  : [27], // escape key
120
				play   : [32], // space - start/stop slideshow
121
				toggle : [70]  // letter "f" - toggle fullscreen
122
			},
123
 
124
			direction : {
125
				next : 'left',
126
				prev : 'right'
127
			},
128
 
129
			scrollOutside  : true,
130
 
131
			// Override some properties
132
			index   : 0,
133
			type    : null,
134
			href    : null,
135
			content : null,
136
			title   : null,
137
 
138
			// HTML templates
139
			tpl: {
140
				wrap     : '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',
141
				image    : '<img class="fancybox-image" src="{href}" alt="" />',
142
				iframe   : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen' + (IE ? ' allowtransparency="true"' : '') + '></iframe>',
143
				error    : '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',
144
				closeBtn : '<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>',
145
				next     : '<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',
146
				prev     : '<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>'
147
			},
148
 
149
			// Properties for each animation type
150
			// Opening fancyBox
151
			openEffect  : 'fade', // 'elastic', 'fade' or 'none'
152
			openSpeed   : 250,
153
			openEasing  : 'swing',
154
			openOpacity : true,
155
			openMethod  : 'zoomIn',
156
 
157
			// Closing fancyBox
158
			closeEffect  : 'fade', // 'elastic', 'fade' or 'none'
159
			closeSpeed   : 250,
160
			closeEasing  : 'swing',
161
			closeOpacity : true,
162
			closeMethod  : 'zoomOut',
163
 
164
			// Changing next gallery item
165
			nextEffect : 'elastic', // 'elastic', 'fade' or 'none'
166
			nextSpeed  : 250,
167
			nextEasing : 'swing',
168
			nextMethod : 'changeIn',
169
 
170
			// Changing previous gallery item
171
			prevEffect : 'elastic', // 'elastic', 'fade' or 'none'
172
			prevSpeed  : 250,
173
			prevEasing : 'swing',
174
			prevMethod : 'changeOut',
175
 
176
			// Enable default helpers
177
			helpers : {
178
				overlay : true,
179
				title   : true
180
			},
181
 
182
			// Callbacks
183
			onCancel     : $.noop, // If canceling
184
			beforeLoad   : $.noop, // Before loading
185
			afterLoad    : $.noop, // After loading
186
			beforeShow   : $.noop, // Before changing in current item
187
			afterShow    : $.noop, // After opening
188
			beforeChange : $.noop, // Before changing gallery item
189
			beforeClose  : $.noop, // Before closing
190
			afterClose   : $.noop  // After closing
191
		},
192
 
193
		//Current state
194
		group    : {}, // Selected group
195
		opts     : {}, // Group options
196
		previous : null,  // Previous element
197
		coming   : null,  // Element being loaded
198
		current  : null,  // Currently loaded element
199
		isActive : false, // Is activated
200
		isOpen   : false, // Is currently open
201
		isOpened : false, // Have been fully opened at least once
202
 
203
		wrap  : null,
204
		skin  : null,
205
		outer : null,
206
		inner : null,
207
 
208
		player : {
209
			timer    : null,
210
			isActive : false
211
		},
212
 
213
		// Loaders
214
		ajaxLoad   : null,
215
		imgPreload : null,
216
 
217
		// Some collections
218
		transitions : {},
219
		helpers     : {},
220
 
221
		/*
222
		 *	Static methods
223
		 */
224
 
225
		open: function (group, opts) {
226
			if (!group) {
227
				return;
228
			}
229
 
230
			if (!$.isPlainObject(opts)) {
231
				opts = {};
232
			}
233
 
234
			// Close if already active
235
			if (false === F.close(true)) {
236
				return;
237
			}
238
 
239
			// Normalize group
240
			if (!$.isArray(group)) {
241
				group = isQuery(group) ? $(group).get() : [group];
242
			}
243
 
244
			// Recheck if the type of each element is `object` and set content type (image, ajax, etc)
245
			$.each(group, function(i, element) {
246
				var obj = {},
247
					href,
248
					title,
249
					content,
250
					type,
251
					rez,
252
					hrefParts,
253
					selector;
254
 
255
				if ($.type(element) === "object") {
256
					// Check if is DOM element
257
					if (element.nodeType) {
258
						element = $(element);
259
					}
260
 
261
					if (isQuery(element)) {
262
						obj = {
263
							href    : element.data('fancybox-href') || element.attr('href'),
264
							title   : element.data('fancybox-title') || element.attr('title'),
265
							isDom   : true,
266
							element : element
267
						};
268
 
269
						if ($.metadata) {
270
							$.extend(true, obj, element.metadata());
271
						}
272
 
273
					} else {
274
						obj = element;
275
					}
276
				}
277
 
278
				href  = opts.href  || obj.href || (isString(element) ? element : null);
279
				title = opts.title !== undefined ? opts.title : obj.title || '';
280
 
281
				content = opts.content || obj.content;
282
				type    = content ? 'html' : (opts.type  || obj.type);
283
 
284
				if (!type && obj.isDom) {
285
					type = element.data('fancybox-type');
286
 
287
					if (!type) {
288
						rez  = element.prop('class').match(/fancybox\.(\w+)/);
289
						type = rez ? rez[1] : null;
290
					}
291
				}
292
 
293
				if (isString(href)) {
294
					// Try to guess the content type
295
					if (!type) {
296
						if (F.isImage(href)) {
297
							type = 'image';
298
 
299
						} else if (F.isSWF(href)) {
300
							type = 'swf';
301
 
302
						} else if (href.charAt(0) === '#') {
303
							type = 'inline';
304
 
305
						} else if (isString(element)) {
306
							type    = 'html';
307
							content = element;
308
						}
309
					}
310
 
311
					// Split url into two pieces with source url and content selector, e.g,
312
					// "/mypage.html #my_id" will load "/mypage.html" and display element having id "my_id"
313
					if (type === 'ajax') {
314
						hrefParts = href.split(/\s+/, 2);
315
						href      = hrefParts.shift();
316
						selector  = hrefParts.shift();
317
					}
318
				}
319
 
320
				if (!content) {
321
					if (type === 'inline') {
322
						if (href) {
323
							content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7
324
 
325
						} else if (obj.isDom) {
326
							content = element;
327
						}
328
 
329
					} else if (type === 'html') {
330
						content = href;
331
 
332
					} else if (!type && !href && obj.isDom) {
333
						type    = 'inline';
334
						content = element;
335
					}
336
				}
337
 
338
				$.extend(obj, {
339
					href     : href,
340
					type     : type,
341
					content  : content,
342
					title    : title,
343
					selector : selector
344
				});
345
 
346
				group[ i ] = obj;
347
			});
348
 
349
			// Extend the defaults
350
			F.opts = $.extend(true, {}, F.defaults, opts);
351
 
352
			// All options are merged recursive except keys
353
			if (opts.keys !== undefined) {
354
				F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false;
355
			}
356
 
357
			F.group = group;
358
 
359
			return F._start(F.opts.index);
360
		},
361
 
362
		// Cancel image loading or abort ajax request
363
		cancel: function () {
364
			var coming = F.coming;
365
 
366
			if (!coming || false === F.trigger('onCancel')) {
367
				return;
368
			}
369
 
370
			F.hideLoading();
371
 
372
			if (F.ajaxLoad) {
373
				F.ajaxLoad.abort();
374
			}
375
 
376
			F.ajaxLoad = null;
377
 
378
			if (F.imgPreload) {
379
				F.imgPreload.onload = F.imgPreload.onerror = null;
380
			}
381
 
382
			if (coming.wrap) {
383
				coming.wrap.stop(true, true).trigger('onReset').remove();
384
			}
385
 
386
			F.coming = null;
387
 
388
			// If the first item has been canceled, then clear everything
389
			if (!F.current) {
390
				F._afterZoomOut( coming );
391
			}
392
		},
393
 
394
		// Start closing animation if is open; remove immediately if opening/closing
395
		close: function (event) {
396
			F.cancel();
397
 
398
			if (false === F.trigger('beforeClose')) {
399
				return;
400
			}
401
 
402
			F.unbindEvents();
403
 
404
			if (!F.isActive) {
405
				return;
406
			}
407
 
408
			if (!F.isOpen || event === true) {
409
				$('.fancybox-wrap').stop(true).trigger('onReset').remove();
410
 
411
				F._afterZoomOut();
412
 
413
			} else {
414
				F.isOpen = F.isOpened = false;
415
				F.isClosing = true;
416
 
417
				$('.fancybox-item, .fancybox-nav').remove();
418
 
419
				F.wrap.stop(true, true).removeClass('fancybox-opened');
420
 
421
				F.transitions[ F.current.closeMethod ]();
422
			}
423
		},
424
 
425
		// Manage slideshow:
426
		//   $.fancybox.play(); - toggle slideshow
427
		//   $.fancybox.play( true ); - start
428
		//   $.fancybox.play( false ); - stop
429
		play: function ( action ) {
430
			var clear = function () {
431
					clearTimeout(F.player.timer);
432
				},
433
				set = function () {
434
					clear();
435
 
436
					if (F.current && F.player.isActive) {
437
						F.player.timer = setTimeout(F.next, F.current.playSpeed);
438
					}
439
				},
440
				stop = function () {
441
					clear();
442
 
443
					D.unbind('.player');
444
 
445
					F.player.isActive = false;
446
 
447
					F.trigger('onPlayEnd');
448
				},
449
				start = function () {
450
					if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) {
451
						F.player.isActive = true;
452
 
453
						D.bind({
454
							'onCancel.player beforeClose.player' : stop,
455
							'onUpdate.player'   : set,
456
							'beforeLoad.player' : clear
457
						});
458
 
459
						set();
460
 
461
						F.trigger('onPlayStart');
462
					}
463
				};
464
 
465
			if (action === true || (!F.player.isActive && action !== false)) {
466
				start();
467
			} else {
468
				stop();
469
			}
470
		},
471
 
472
		// Navigate to next gallery item
473
		next: function ( direction ) {
474
			var current = F.current;
475
 
476
			if (current) {
477
				if (!isString(direction)) {
478
					direction = current.direction.next;
479
				}
480
 
481
				F.jumpto(current.index + 1, direction, 'next');
482
			}
483
		},
484
 
485
		// Navigate to previous gallery item
486
		prev: function ( direction ) {
487
			var current = F.current;
488
 
489
			if (current) {
490
				if (!isString(direction)) {
491
					direction = current.direction.prev;
492
				}
493
 
494
				F.jumpto(current.index - 1, direction, 'prev');
495
			}
496
		},
497
 
498
		// Navigate to gallery item by index
499
		jumpto: function ( index, direction, router ) {
500
			var current = F.current;
501
 
502
			if (!current) {
503
				return;
504
			}
505
 
506
			index = getScalar(index);
507
 
508
			F.direction = direction || current.direction[ (index >= current.index ? 'next' : 'prev') ];
509
			F.router    = router || 'jumpto';
510
 
511
			if (current.loop) {
512
				if (index < 0) {
513
					index = current.group.length + (index % current.group.length);
514
				}
515
 
516
				index = index % current.group.length;
517
			}
518
 
519
			if (current.group[ index ] !== undefined) {
520
				F.cancel();
521
 
522
				F._start(index);
523
			}
524
		},
525
 
526
		// Center inside viewport and toggle position type to fixed or absolute if needed
527
		reposition: function (e, onlyAbsolute) {
528
			var current = F.current,
529
				wrap    = current ? current.wrap : null,
530
				pos;
531
 
532
			if (wrap) {
533
				pos = F._getPosition(onlyAbsolute);
534
 
535
				if (e && e.type === 'scroll') {
536
					delete pos.position;
537
 
538
					wrap.stop(true, true).animate(pos, 200);
539
 
540
				} else {
541
					wrap.css(pos);
542
 
543
					current.pos = $.extend({}, current.dim, pos);
544
				}
545
			}
546
		},
547
 
548
		update: function (e) {
549
			var type = (e && e.type),
550
				anyway = !type || type === 'orientationchange';
551
 
552
			if (anyway) {
553
				clearTimeout(didUpdate);
554
 
555
				didUpdate = null;
556
			}
557
 
558
			if (!F.isOpen || didUpdate) {
559
				return;
560
			}
561
 
562
			didUpdate = setTimeout(function() {
563
				var current = F.current;
564
 
565
				if (!current || F.isClosing) {
566
					return;
567
				}
568
 
569
				F.wrap.removeClass('fancybox-tmp');
570
 
571
				if (anyway || type === 'load' || (type === 'resize' && current.autoResize)) {
572
					F._setDimension();
573
				}
574
 
575
				if (!(type === 'scroll' && current.canShrink)) {
576
					F.reposition(e);
577
				}
578
 
579
				F.trigger('onUpdate');
580
 
581
				didUpdate = null;
582
 
583
			}, (anyway && !isTouch ? 0 : 300));
584
		},
585
 
586
		// Shrink content to fit inside viewport or restore if resized
587
		toggle: function ( action ) {
588
			if (F.isOpen) {
589
				F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView;
590
 
591
				// Help browser to restore document dimensions
592
				if (isTouch) {
593
					F.wrap.removeAttr('style').addClass('fancybox-tmp');
594
 
595
					F.trigger('onUpdate');
596
				}
597
 
598
				F.update();
599
			}
600
		},
601
 
602
		hideLoading: function () {
603
			D.unbind('.loading');
604
 
605
			$('#fancybox-loading').remove();
606
		},
607
 
608
		showLoading: function () {
609
			var el, viewport;
610
 
611
			F.hideLoading();
612
 
613
			el = $('<div id="fancybox-loading"><div></div></div>').click(F.cancel).appendTo('body');
614
 
615
			// If user will press the escape-button, the request will be canceled
616
			D.bind('keydown.loading', function(e) {
617
				if ((e.which || e.keyCode) === 27) {
618
					e.preventDefault();
619
 
620
					F.cancel();
621
				}
622
			});
623
 
624
			if (!F.defaults.fixed) {
625
				viewport = F.getViewport();
626
 
627
				el.css({
628
					position : 'absolute',
629
					top  : (viewport.h * 0.5) + viewport.y,
630
					left : (viewport.w * 0.5) + viewport.x
631
				});
632
			}
633
		},
634
 
635
		getViewport: function () {
636
			var locked = (F.current && F.current.locked) || false,
637
				rez    = {
638
					x: W.scrollLeft(),
639
					y: W.scrollTop()
640
				};
641
 
642
			if (locked) {
643
				rez.w = locked[0].clientWidth;
644
				rez.h = locked[0].clientHeight;
645
 
646
			} else {
647
				// See http://bugs.jquery.com/ticket/6724
648
				rez.w = isTouch && window.innerWidth  ? window.innerWidth  : W.width();
649
				rez.h = isTouch && window.innerHeight ? window.innerHeight : W.height();
650
			}
651
 
652
			return rez;
653
		},
654
 
655
		// Unbind the keyboard / clicking actions
656
		unbindEvents: function () {
657
			if (F.wrap && isQuery(F.wrap)) {
658
				F.wrap.unbind('.fb');
659
			}
660
 
661
			D.unbind('.fb');
662
			W.unbind('.fb');
663
		},
664
 
665
		bindEvents: function () {
666
			var current = F.current,
667
				keys;
668
 
669
			if (!current) {
670
				return;
671
			}
672
 
673
			// Changing document height on iOS devices triggers a 'resize' event,
674
			// that can change document height... repeating infinitely
675
			W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update);
676
 
677
			keys = current.keys;
678
 
679
			if (keys) {
680
				D.bind('keydown.fb', function (e) {
681
					var code   = e.which || e.keyCode,
682
						target = e.target || e.srcElement;
683
 
684
					// Skip esc key if loading, because showLoading will cancel preloading
685
					if (code === 27 && F.coming) {
686
						return false;
687
					}
688
 
689
					// Ignore key combinations and key events within form elements
690
					if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) {
691
						$.each(keys, function(i, val) {
692
							if (current.group.length > 1 && val[ code ] !== undefined) {
693
								F[ i ]( val[ code ] );
694
 
695
								e.preventDefault();
696
								return false;
697
							}
698
 
699
							if ($.inArray(code, val) > -1) {
700
								F[ i ] ();
701
 
702
								e.preventDefault();
703
								return false;
704
							}
705
						});
706
					}
707
				});
708
			}
709
 
710
			if ($.fn.mousewheel && current.mouseWheel) {
711
				F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) {
712
					var target = e.target || null,
713
						parent = $(target),
714
						canScroll = false;
715
 
716
					while (parent.length) {
717
						if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) {
718
							break;
719
						}
720
 
721
						canScroll = isScrollable( parent[0] );
722
						parent    = $(parent).parent();
723
					}
724
 
725
					if (delta !== 0 && !canScroll) {
726
						if (F.group.length > 1 && !current.canShrink) {
727
							if (deltaY > 0 || deltaX > 0) {
728
								F.prev( deltaY > 0 ? 'down' : 'left' );
729
 
730
							} else if (deltaY < 0 || deltaX < 0) {
731
								F.next( deltaY < 0 ? 'up' : 'right' );
732
							}
733
 
734
							e.preventDefault();
735
						}
736
					}
737
				});
738
			}
739
		},
740
 
741
		trigger: function (event, o) {
742
			var ret, obj = o || F.coming || F.current;
743
 
744
			if (!obj) {
745
				return;
746
			}
747
 
748
			if ($.isFunction( obj[event] )) {
749
				ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1));
750
			}
751
 
752
			if (ret === false) {
753
				return false;
754
			}
755
 
756
			if (obj.helpers) {
757
				$.each(obj.helpers, function (helper, opts) {
758
					if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) {
759
						F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj);
760
					}
761
				});
762
			}
763
 
764
			D.trigger(event);
765
		},
766
 
767
		isImage: function (str) {
768
			return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i);
769
		},
770
 
771
		isSWF: function (str) {
772
			return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i);
773
		},
774
 
775
		_start: function (index) {
776
			var coming = {},
777
				obj,
778
				href,
779
				type,
780
				margin,
781
				padding;
782
 
783
			index = getScalar( index );
784
			obj   = F.group[ index ] || null;
785
 
786
			if (!obj) {
787
				return false;
788
			}
789
 
790
			coming = $.extend(true, {}, F.opts, obj);
791
 
792
			// Convert margin and padding properties to array - top, right, bottom, left
793
			margin  = coming.margin;
794
			padding = coming.padding;
795
 
796
			if ($.type(margin) === 'number') {
797
				coming.margin = [margin, margin, margin, margin];
798
			}
799
 
800
			if ($.type(padding) === 'number') {
801
				coming.padding = [padding, padding, padding, padding];
802
			}
803
 
804
			// 'modal' propery is just a shortcut
805
			if (coming.modal) {
806
				$.extend(true, coming, {
807
					closeBtn   : false,
808
					closeClick : false,
809
					nextClick  : false,
810
					arrows     : false,
811
					mouseWheel : false,
812
					keys       : null,
813
					helpers: {
814
						overlay : {
815
							closeClick : false
816
						}
817
					}
818
				});
819
			}
820
 
821
			// 'autoSize' property is a shortcut, too
822
			if (coming.autoSize) {
823
				coming.autoWidth = coming.autoHeight = true;
824
			}
825
 
826
			if (coming.width === 'auto') {
827
				coming.autoWidth = true;
828
			}
829
 
830
			if (coming.height === 'auto') {
831
				coming.autoHeight = true;
832
			}
833
 
834
			/*
835
			 * Add reference to the group, so it`s possible to access from callbacks, example:
836
			 * afterLoad : function() {
837
			 *     this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
838
			 * }
839
			 */
840
 
841
			coming.group  = F.group;
842
			coming.index  = index;
843
 
844
			// Give a chance for callback or helpers to update coming item (type, title, etc)
845
			F.coming = coming;
846
 
847
			if (false === F.trigger('beforeLoad')) {
848
				F.coming = null;
849
 
850
				return;
851
			}
852
 
853
			type = coming.type;
854
			href = coming.href;
855
 
856
			if (!type) {
857
				F.coming = null;
858
 
859
				//If we can not determine content type then drop silently or display next/prev item if looping through gallery
860
				if (F.current && F.router && F.router !== 'jumpto') {
861
					F.current.index = index;
862
 
863
					return F[ F.router ]( F.direction );
864
				}
865
 
866
				return false;
867
			}
868
 
869
			F.isActive = true;
870
 
871
			if (type === 'image' || type === 'swf') {
872
				coming.autoHeight = coming.autoWidth = false;
873
				coming.scrolling  = 'visible';
874
			}
875
 
876
			if (type === 'image') {
877
				coming.aspectRatio = true;
878
			}
879
 
880
			if (type === 'iframe' && isTouch) {
881
				coming.scrolling = 'scroll';
882
			}
883
 
884
			// Build the neccessary markup
885
			coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo( coming.parent || 'body' );
886
 
887
			$.extend(coming, {
888
				skin  : $('.fancybox-skin',  coming.wrap),
889
				outer : $('.fancybox-outer', coming.wrap),
890
				inner : $('.fancybox-inner', coming.wrap)
891
			});
892
 
893
			$.each(["Top", "Right", "Bottom", "Left"], function(i, v) {
894
				coming.skin.css('padding' + v, getValue(coming.padding[ i ]));
895
			});
896
 
897
			F.trigger('onReady');
898
 
899
			// Check before try to load; 'inline' and 'html' types need content, others - href
900
			if (type === 'inline' || type === 'html') {
901
				if (!coming.content || !coming.content.length) {
902
					return F._error( 'content' );
903
				}
904
 
905
			} else if (!href) {
906
				return F._error( 'href' );
907
			}
908
 
909
			if (type === 'image') {
910
				F._loadImage();
911
 
912
			} else if (type === 'ajax') {
913
				F._loadAjax();
914
 
915
			} else if (type === 'iframe') {
916
				F._loadIframe();
917
 
918
			} else {
919
				F._afterLoad();
920
			}
921
		},
922
 
923
		_error: function ( type ) {
924
			$.extend(F.coming, {
925
				type       : 'html',
926
				autoWidth  : true,
927
				autoHeight : true,
928
				minWidth   : 0,
929
				minHeight  : 0,
930
				scrolling  : 'no',
931
				hasError   : type,
932
				content    : F.coming.tpl.error
933
			});
934
 
935
			F._afterLoad();
936
		},
937
 
938
		_loadImage: function () {
939
			// Reset preload image so it is later possible to check "complete" property
940
			var img = F.imgPreload = new Image();
941
 
942
			img.onload = function () {
943
				this.onload = this.onerror = null;
944
 
945
				F.coming.width  = this.width / F.opts.pixelRatio;
946
				F.coming.height = this.height / F.opts.pixelRatio;
947
 
948
				F._afterLoad();
949
			};
950
 
951
			img.onerror = function () {
952
				this.onload = this.onerror = null;
953
 
954
				F._error( 'image' );
955
			};
956
 
957
			img.src = F.coming.href;
958
 
959
			if (img.complete !== true) {
960
				F.showLoading();
961
			}
962
		},
963
 
964
		_loadAjax: function () {
965
			var coming = F.coming;
966
 
967
			F.showLoading();
968
 
969
			F.ajaxLoad = $.ajax($.extend({}, coming.ajax, {
970
				url: coming.href,
971
				error: function (jqXHR, textStatus) {
972
					if (F.coming && textStatus !== 'abort') {
973
						F._error( 'ajax', jqXHR );
974
 
975
					} else {
976
						F.hideLoading();
977
					}
978
				},
979
				success: function (data, textStatus) {
980
					if (textStatus === 'success') {
981
						coming.content = data;
982
 
983
						F._afterLoad();
984
					}
985
				}
986
			}));
987
		},
988
 
989
		_loadIframe: function() {
990
			var coming = F.coming,
991
				iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime()))
992
					.attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling)
993
					.attr('src', coming.href);
994
 
995
			// This helps IE
996
			$(coming.wrap).bind('onReset', function () {
997
				try {
998
					$(this).find('iframe').hide().attr('src', '//about:blank').end().empty();
999
				} catch (e) {}
1000
			});
1001
 
1002
			if (coming.iframe.preload) {
1003
				F.showLoading();
1004
 
1005
				iframe.one('load', function() {
1006
					$(this).data('ready', 1);
1007
 
1008
					// iOS will lose scrolling if we resize
1009
					if (!isTouch) {
1010
						$(this).bind('load.fb', F.update);
1011
					}
1012
 
1013
					// Without this trick:
1014
					//   - iframe won't scroll on iOS devices
1015
					//   - IE7 sometimes displays empty iframe
1016
					$(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show();
1017
 
1018
					F._afterLoad();
1019
				});
1020
			}
1021
 
1022
			coming.content = iframe.appendTo( coming.inner );
1023
 
1024
			if (!coming.iframe.preload) {
1025
				F._afterLoad();
1026
			}
1027
		},
1028
 
1029
		_preloadImages: function() {
1030
			var group   = F.group,
1031
				current = F.current,
1032
				len     = group.length,
1033
				cnt     = current.preload ? Math.min(current.preload, len - 1) : 0,
1034
				item,
1035
				i;
1036
 
1037
			for (i = 1; i <= cnt; i += 1) {
1038
				item = group[ (current.index + i ) % len ];
1039
 
1040
				if (item.type === 'image' && item.href) {
1041
					new Image().src = item.href;
1042
				}
1043
			}
1044
		},
1045
 
1046
		_afterLoad: function () {
1047
			var coming   = F.coming,
1048
				previous = F.current,
1049
				placeholder = 'fancybox-placeholder',
1050
				current,
1051
				content,
1052
				type,
1053
				scrolling,
1054
				href,
1055
				embed;
1056
 
1057
			F.hideLoading();
1058
 
1059
			if (!coming || F.isActive === false) {
1060
				return;
1061
			}
1062
 
1063
			if (false === F.trigger('afterLoad', coming, previous)) {
1064
				coming.wrap.stop(true).trigger('onReset').remove();
1065
 
1066
				F.coming = null;
1067
 
1068
				return;
1069
			}
1070
 
1071
			if (previous) {
1072
				F.trigger('beforeChange', previous);
1073
 
1074
				previous.wrap.stop(true).removeClass('fancybox-opened')
1075
					.find('.fancybox-item, .fancybox-nav')
1076
					.remove();
1077
			}
1078
 
1079
			F.unbindEvents();
1080
 
1081
			current   = coming;
1082
			content   = coming.content;
1083
			type      = coming.type;
1084
			scrolling = coming.scrolling;
1085
 
1086
			$.extend(F, {
1087
				wrap  : current.wrap,
1088
				skin  : current.skin,
1089
				outer : current.outer,
1090
				inner : current.inner,
1091
				current  : current,
1092
				previous : previous
1093
			});
1094
 
1095
			href = current.href;
1096
 
1097
			switch (type) {
1098
				case 'inline':
1099
				case 'ajax':
1100
				case 'html':
1101
					if (current.selector) {
1102
						content = $('<div>').html(content).find(current.selector);
1103
 
1104
					} else if (isQuery(content)) {
1105
						if (!content.data(placeholder)) {
1106
							content.data(placeholder, $('<div class="' + placeholder + '"></div>').insertAfter( content ).hide() );
1107
						}
1108
 
1109
						content = content.show().detach();
1110
 
1111
						current.wrap.bind('onReset', function () {
1112
							if ($(this).find(content).length) {
1113
								content.hide().replaceAll( content.data(placeholder) ).data(placeholder, false);
1114
							}
1115
						});
1116
					}
1117
				break;
1118
 
1119
				case 'image':
1120
					content = current.tpl.image.replace('{href}', href);
1121
				break;
1122
 
1123
				case 'swf':
1124
					content = '<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="' + href + '"></param>';
1125
					embed   = '';
1126
 
1127
					$.each(current.swf, function(name, val) {
1128
						content += '<param name="' + name + '" value="' + val + '"></param>';
1129
						embed   += ' ' + name + '="' + val + '"';
1130
					});
1131
 
1132
					content += '<embed src="' + href + '" type="application/x-shockwave-flash" width="100%" height="100%"' + embed + '></embed></object>';
1133
				break;
1134
			}
1135
 
1136
			if (!(isQuery(content) && content.parent().is(current.inner))) {
1137
				current.inner.append( content );
1138
			}
1139
 
1140
			// Give a chance for helpers or callbacks to update elements
1141
			F.trigger('beforeShow');
1142
 
1143
			// Set scrolling before calculating dimensions
1144
			current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling));
1145
 
1146
			// Set initial dimensions and start position
1147
			F._setDimension();
1148
 
1149
			F.reposition();
1150
 
1151
			F.isOpen = false;
1152
			F.coming = null;
1153
 
1154
			F.bindEvents();
1155
 
1156
			if (!F.isOpened) {
1157
				$('.fancybox-wrap').not( current.wrap ).stop(true).trigger('onReset').remove();
1158
 
1159
			} else if (previous.prevMethod) {
1160
				F.transitions[ previous.prevMethod ]();
1161
			}
1162
 
1163
			F.transitions[ F.isOpened ? current.nextMethod : current.openMethod ]();
1164
 
1165
			F._preloadImages();
1166
		},
1167
 
1168
		_setDimension: function () {
1169
			var viewport   = F.getViewport(),
1170
				steps      = 0,
1171
				canShrink  = false,
1172
				canExpand  = false,
1173
				wrap       = F.wrap,
1174
				skin       = F.skin,
1175
				inner      = F.inner,
1176
				current    = F.current,
1177
				width      = current.width,
1178
				height     = current.height,
1179
				minWidth   = current.minWidth,
1180
				minHeight  = current.minHeight,
1181
				maxWidth   = current.maxWidth,
1182
				maxHeight  = current.maxHeight,
1183
				scrolling  = current.scrolling,
1184
				scrollOut  = current.scrollOutside ? current.scrollbarWidth : 0,
1185
				margin     = current.margin,
1186
				wMargin    = getScalar(margin[1] + margin[3]),
1187
				hMargin    = getScalar(margin[0] + margin[2]),
1188
				wPadding,
1189
				hPadding,
1190
				wSpace,
1191
				hSpace,
1192
				origWidth,
1193
				origHeight,
1194
				origMaxWidth,
1195
				origMaxHeight,
1196
				ratio,
1197
				width_,
1198
				height_,
1199
				maxWidth_,
1200
				maxHeight_,
1201
				iframe,
1202
				body;
1203
 
1204
			// Reset dimensions so we could re-check actual size
1205
			wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp');
1206
 
1207
			wPadding = getScalar(skin.outerWidth(true)  - skin.width());
1208
			hPadding = getScalar(skin.outerHeight(true) - skin.height());
1209
 
1210
			// Any space between content and viewport (margin, padding, border, title)
1211
			wSpace = wMargin + wPadding;
1212
			hSpace = hMargin + hPadding;
1213
 
1214
			origWidth  = isPercentage(width)  ? (viewport.w - wSpace) * getScalar(width)  / 100 : width;
1215
			origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height;
1216
 
1217
			if (current.type === 'iframe') {
1218
				iframe = current.content;
1219
 
1220
				if (current.autoHeight && iframe.data('ready') === 1) {
1221
					try {
1222
						if (iframe[0].contentWindow.document.location) {
1223
							inner.width( origWidth ).height(9999);
1224
 
1225
							body = iframe.contents().find('body');
1226
 
1227
							if (scrollOut) {
1228
								body.css('overflow-x', 'hidden');
1229
							}
1230
 
1231
							origHeight = body.outerHeight(true);
1232
						}
1233
 
1234
					} catch (e) {}
1235
				}
1236
 
1237
			} else if (current.autoWidth || current.autoHeight) {
1238
				inner.addClass( 'fancybox-tmp' );
1239
 
1240
				// Set width or height in case we need to calculate only one dimension
1241
				if (!current.autoWidth) {
1242
					inner.width( origWidth );
1243
				}
1244
 
1245
				if (!current.autoHeight) {
1246
					inner.height( origHeight );
1247
				}
1248
 
1249
				if (current.autoWidth) {
1250
					origWidth = inner.width();
1251
				}
1252
 
1253
				if (current.autoHeight) {
1254
					origHeight = inner.height();
1255
				}
1256
 
1257
				inner.removeClass( 'fancybox-tmp' );
1258
			}
1259
 
1260
			width  = getScalar( origWidth );
1261
			height = getScalar( origHeight );
1262
 
1263
			ratio  = origWidth / origHeight;
1264
 
1265
			// Calculations for the content
1266
			minWidth  = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth);
1267
			maxWidth  = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth);
1268
 
1269
			minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight);
1270
			maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight);
1271
 
1272
			// These will be used to determine if wrap can fit in the viewport
1273
			origMaxWidth  = maxWidth;
1274
			origMaxHeight = maxHeight;
1275
 
1276
			if (current.fitToView) {
1277
				maxWidth  = Math.min(viewport.w - wSpace, maxWidth);
1278
				maxHeight = Math.min(viewport.h - hSpace, maxHeight);
1279
			}
1280
 
1281
			maxWidth_  = viewport.w - wMargin;
1282
			maxHeight_ = viewport.h - hMargin;
1283
 
1284
			if (current.aspectRatio) {
1285
				if (width > maxWidth) {
1286
					width  = maxWidth;
1287
					height = getScalar(width / ratio);
1288
				}
1289
 
1290
				if (height > maxHeight) {
1291
					height = maxHeight;
1292
					width  = getScalar(height * ratio);
1293
				}
1294
 
1295
				if (width < minWidth) {
1296
					width  = minWidth;
1297
					height = getScalar(width / ratio);
1298
				}
1299
 
1300
				if (height < minHeight) {
1301
					height = minHeight;
1302
					width  = getScalar(height * ratio);
1303
				}
1304
 
1305
			} else {
1306
				width = Math.max(minWidth, Math.min(width, maxWidth));
1307
 
1308
				if (current.autoHeight && current.type !== 'iframe') {
1309
					inner.width( width );
1310
 
1311
					height = inner.height();
1312
				}
1313
 
1314
				height = Math.max(minHeight, Math.min(height, maxHeight));
1315
			}
1316
 
1317
			// Try to fit inside viewport (including the title)
1318
			if (current.fitToView) {
1319
				inner.width( width ).height( height );
1320
 
1321
				wrap.width( width + wPadding );
1322
 
1323
				// Real wrap dimensions
1324
				width_  = wrap.width();
1325
				height_ = wrap.height();
1326
 
1327
				if (current.aspectRatio) {
1328
					while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) {
1329
						if (steps++ > 19) {
1330
							break;
1331
						}
1332
 
1333
						height = Math.max(minHeight, Math.min(maxHeight, height - 10));
1334
						width  = getScalar(height * ratio);
1335
 
1336
						if (width < minWidth) {
1337
							width  = minWidth;
1338
							height = getScalar(width / ratio);
1339
						}
1340
 
1341
						if (width > maxWidth) {
1342
							width  = maxWidth;
1343
							height = getScalar(width / ratio);
1344
						}
1345
 
1346
						inner.width( width ).height( height );
1347
 
1348
						wrap.width( width + wPadding );
1349
 
1350
						width_  = wrap.width();
1351
						height_ = wrap.height();
1352
					}
1353
 
1354
				} else {
1355
					width  = Math.max(minWidth,  Math.min(width,  width  - (width_  - maxWidth_)));
1356
					height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_)));
1357
				}
1358
			}
1359
 
1360
			if (scrollOut && scrolling === 'auto' && height < origHeight && (width + wPadding + scrollOut) < maxWidth_) {
1361
				width += scrollOut;
1362
			}
1363
 
1364
			inner.width( width ).height( height );
1365
 
1366
			wrap.width( width + wPadding );
1367
 
1368
			width_  = wrap.width();
1369
			height_ = wrap.height();
1370
 
1371
			canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight;
1372
			canExpand = current.aspectRatio ? (width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight) : ((width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight));
1373
 
1374
			$.extend(current, {
1375
				dim : {
1376
					width	: getValue( width_ ),
1377
					height	: getValue( height_ )
1378
				},
1379
				origWidth  : origWidth,
1380
				origHeight : origHeight,
1381
				canShrink  : canShrink,
1382
				canExpand  : canExpand,
1383
				wPadding   : wPadding,
1384
				hPadding   : hPadding,
1385
				wrapSpace  : height_ - skin.outerHeight(true),
1386
				skinSpace  : skin.height() - height
1387
			});
1388
 
1389
			if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) {
1390
				inner.height('auto');
1391
			}
1392
		},
1393
 
1394
		_getPosition: function (onlyAbsolute) {
1395
			var current  = F.current,
1396
				viewport = F.getViewport(),
1397
				margin   = current.margin,
1398
				width    = F.wrap.width()  + margin[1] + margin[3],
1399
				height   = F.wrap.height() + margin[0] + margin[2],
1400
				rez      = {
1401
					position: 'absolute',
1402
					top  : margin[0],
1403
					left : margin[3]
1404
				};
1405
 
1406
			if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) {
1407
				rez.position = 'fixed';
1408
 
1409
			} else if (!current.locked) {
1410
				rez.top  += viewport.y;
1411
				rez.left += viewport.x;
1412
			}
1413
 
1414
			rez.top  = getValue(Math.max(rez.top,  rez.top  + ((viewport.h - height) * current.topRatio)));
1415
			rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width)  * current.leftRatio)));
1416
 
1417
			return rez;
1418
		},
1419
 
1420
		_afterZoomIn: function () {
1421
			var current = F.current;
1422
 
1423
			if (!current) {
1424
				return;
1425
			}
1426
 
1427
			F.isOpen = F.isOpened = true;
1428
 
1429
			F.wrap.css('overflow', 'visible').addClass('fancybox-opened');
1430
 
1431
			F.update();
1432
 
1433
			// Assign a click event
1434
			if ( current.closeClick || (current.nextClick && F.group.length > 1) ) {
1435
				F.inner.css('cursor', 'pointer').bind('click.fb', function(e) {
1436
					if (!$(e.target).is('a') && !$(e.target).parent().is('a')) {
1437
						e.preventDefault();
1438
 
1439
						F[ current.closeClick ? 'close' : 'next' ]();
1440
					}
1441
				});
1442
			}
1443
 
1444
			// Create a close button
1445
			if (current.closeBtn) {
1446
				$(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) {
1447
					e.preventDefault();
1448
 
1449
					F.close();
1450
				});
1451
			}
1452
 
1453
			// Create navigation arrows
1454
			if (current.arrows && F.group.length > 1) {
1455
				if (current.loop || current.index > 0) {
1456
					$(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev);
1457
				}
1458
 
1459
				if (current.loop || current.index < F.group.length - 1) {
1460
					$(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next);
1461
				}
1462
			}
1463
 
1464
			F.trigger('afterShow');
1465
 
1466
			// Stop the slideshow if this is the last item
1467
			if (!current.loop && current.index === current.group.length - 1) {
1468
				F.play( false );
1469
 
1470
			} else if (F.opts.autoPlay && !F.player.isActive) {
1471
				F.opts.autoPlay = false;
1472
 
1473
				F.play();
1474
			}
1475
		},
1476
 
1477
		_afterZoomOut: function ( obj ) {
1478
			obj = obj || F.current;
1479
 
1480
			$('.fancybox-wrap').trigger('onReset').remove();
1481
 
1482
			$.extend(F, {
1483
				group  : {},
1484
				opts   : {},
1485
				router : false,
1486
				current   : null,
1487
				isActive  : false,
1488
				isOpened  : false,
1489
				isOpen    : false,
1490
				isClosing : false,
1491
				wrap   : null,
1492
				skin   : null,
1493
				outer  : null,
1494
				inner  : null
1495
			});
1496
 
1497
			F.trigger('afterClose', obj);
1498
		}
1499
	});
1500
 
1501
	/*
1502
	 *	Default transitions
1503
	 */
1504
 
1505
	F.transitions = {
1506
		getOrigPosition: function () {
1507
			var current  = F.current,
1508
				element  = current.element,
1509
				orig     = current.orig,
1510
				pos      = {},
1511
				width    = 50,
1512
				height   = 50,
1513
				hPadding = current.hPadding,
1514
				wPadding = current.wPadding,
1515
				viewport = F.getViewport();
1516
 
1517
			if (!orig && current.isDom && element.is(':visible')) {
1518
				orig = element.find('img:first');
1519
 
1520
				if (!orig.length) {
1521
					orig = element;
1522
				}
1523
			}
1524
 
1525
			if (isQuery(orig)) {
1526
				pos = orig.offset();
1527
 
1528
				if (orig.is('img')) {
1529
					width  = orig.outerWidth();
1530
					height = orig.outerHeight();
1531
				}
1532
 
1533
			} else {
1534
				pos.top  = viewport.y + (viewport.h - height) * current.topRatio;
1535
				pos.left = viewport.x + (viewport.w - width)  * current.leftRatio;
1536
			}
1537
 
1538
			if (F.wrap.css('position') === 'fixed' || current.locked) {
1539
				pos.top  -= viewport.y;
1540
				pos.left -= viewport.x;
1541
			}
1542
 
1543
			pos = {
1544
				top     : getValue(pos.top  - hPadding * current.topRatio),
1545
				left    : getValue(pos.left - wPadding * current.leftRatio),
1546
				width   : getValue(width  + wPadding),
1547
				height  : getValue(height + hPadding)
1548
			};
1549
 
1550
			return pos;
1551
		},
1552
 
1553
		step: function (now, fx) {
1554
			var ratio,
1555
				padding,
1556
				value,
1557
				prop       = fx.prop,
1558
				current    = F.current,
1559
				wrapSpace  = current.wrapSpace,
1560
				skinSpace  = current.skinSpace;
1561
 
1562
			if (prop === 'width' || prop === 'height') {
1563
				ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start);
1564
 
1565
				if (F.isClosing) {
1566
					ratio = 1 - ratio;
1567
				}
1568
 
1569
				padding = prop === 'width' ? current.wPadding : current.hPadding;
1570
				value   = now - padding;
1571
 
1572
				F.skin[ prop ](  getScalar( prop === 'width' ?  value : value - (wrapSpace * ratio) ) );
1573
				F.inner[ prop ]( getScalar( prop === 'width' ?  value : value - (wrapSpace * ratio) - (skinSpace * ratio) ) );
1574
			}
1575
		},
1576
 
1577
		zoomIn: function () {
1578
			var current  = F.current,
1579
				startPos = current.pos,
1580
				effect   = current.openEffect,
1581
				elastic  = effect === 'elastic',
1582
				endPos   = $.extend({opacity : 1}, startPos);
1583
 
1584
			// Remove "position" property that breaks older IE
1585
			delete endPos.position;
1586
 
1587
			if (elastic) {
1588
				startPos = this.getOrigPosition();
1589
 
1590
				if (current.openOpacity) {
1591
					startPos.opacity = 0.1;
1592
				}
1593
 
1594
			} else if (effect === 'fade') {
1595
				startPos.opacity = 0.1;
1596
			}
1597
 
1598
			F.wrap.css(startPos).animate(endPos, {
1599
				duration : effect === 'none' ? 0 : current.openSpeed,
1600
				easing   : current.openEasing,
1601
				step     : elastic ? this.step : null,
1602
				complete : F._afterZoomIn
1603
			});
1604
		},
1605
 
1606
		zoomOut: function () {
1607
			var current  = F.current,
1608
				effect   = current.closeEffect,
1609
				elastic  = effect === 'elastic',
1610
				endPos   = {opacity : 0.1};
1611
 
1612
			if (elastic) {
1613
				endPos = this.getOrigPosition();
1614
 
1615
				if (current.closeOpacity) {
1616
					endPos.opacity = 0.1;
1617
				}
1618
			}
1619
 
1620
			F.wrap.animate(endPos, {
1621
				duration : effect === 'none' ? 0 : current.closeSpeed,
1622
				easing   : current.closeEasing,
1623
				step     : elastic ? this.step : null,
1624
				complete : F._afterZoomOut
1625
			});
1626
		},
1627
 
1628
		changeIn: function () {
1629
			var current   = F.current,
1630
				effect    = current.nextEffect,
1631
				startPos  = current.pos,
1632
				endPos    = { opacity : 1 },
1633
				direction = F.direction,
1634
				distance  = 200,
1635
				field;
1636
 
1637
			startPos.opacity = 0.1;
1638
 
1639
			if (effect === 'elastic') {
1640
				field = direction === 'down' || direction === 'up' ? 'top' : 'left';
1641
 
1642
				if (direction === 'down' || direction === 'right') {
1643
					startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance);
1644
					endPos[ field ]   = '+=' + distance + 'px';
1645
 
1646
				} else {
1647
					startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance);
1648
					endPos[ field ]   = '-=' + distance + 'px';
1649
				}
1650
			}
1651
 
1652
			// Workaround for http://bugs.jquery.com/ticket/12273
1653
			if (effect === 'none') {
1654
				F._afterZoomIn();
1655
 
1656
			} else {
1657
				F.wrap.css(startPos).animate(endPos, {
1658
					duration : current.nextSpeed,
1659
					easing   : current.nextEasing,
1660
					complete : F._afterZoomIn
1661
				});
1662
			}
1663
		},
1664
 
1665
		changeOut: function () {
1666
			var previous  = F.previous,
1667
				effect    = previous.prevEffect,
1668
				endPos    = { opacity : 0.1 },
1669
				direction = F.direction,
1670
				distance  = 200;
1671
 
1672
			if (effect === 'elastic') {
1673
				endPos[ direction === 'down' || direction === 'up' ? 'top' : 'left' ] = ( direction === 'up' || direction === 'left' ? '-' : '+' ) + '=' + distance + 'px';
1674
			}
1675
 
1676
			previous.wrap.animate(endPos, {
1677
				duration : effect === 'none' ? 0 : previous.prevSpeed,
1678
				easing   : previous.prevEasing,
1679
				complete : function () {
1680
					$(this).trigger('onReset').remove();
1681
				}
1682
			});
1683
		}
1684
	};
1685
 
1686
	/*
1687
	 *	Overlay helper
1688
	 */
1689
 
1690
	F.helpers.overlay = {
1691
		defaults : {
1692
			closeClick : true,      // if true, fancyBox will be closed when user clicks on the overlay
1693
			speedOut   : 200,       // duration of fadeOut animation
1694
			showEarly  : true,      // indicates if should be opened immediately or wait until the content is ready
1695
			css        : {},        // custom CSS properties
1696
			locked     : !isTouch,  // if true, the content will be locked into overlay
1697
			fixed      : true       // if false, the overlay CSS position property will not be set to "fixed"
1698
		},
1699
 
1700
		overlay : null,      // current handle
1701
		fixed   : false,     // indicates if the overlay has position "fixed"
1702
		el      : $('html'), // element that contains "the lock"
1703
 
1704
		// Public methods
1705
		create : function(opts) {
1706
			opts = $.extend({}, this.defaults, opts);
1707
 
1708
			if (this.overlay) {
1709
				this.close();
1710
			}
1711
 
1712
			this.overlay = $('<div class="fancybox-overlay"></div>').appendTo( F.coming ? F.coming.parent : opts.parent );
1713
			this.fixed   = false;
1714
 
1715
			if (opts.fixed && F.defaults.fixed) {
1716
				this.overlay.addClass('fancybox-overlay-fixed');
1717
 
1718
				this.fixed = true;
1719
			}
1720
		},
1721
 
1722
		open : function(opts) {
1723
			var that = this;
1724
 
1725
			opts = $.extend({}, this.defaults, opts);
1726
 
1727
			if (this.overlay) {
1728
				this.overlay.unbind('.overlay').width('auto').height('auto');
1729
 
1730
			} else {
1731
				this.create(opts);
1732
			}
1733
 
1734
			if (!this.fixed) {
1735
				W.bind('resize.overlay', $.proxy( this.update, this) );
1736
 
1737
				this.update();
1738
			}
1739
 
1740
			if (opts.closeClick) {
1741
				this.overlay.bind('click.overlay', function(e) {
1742
					if ($(e.target).hasClass('fancybox-overlay')) {
1743
						if (F.isActive) {
1744
							F.close();
1745
						} else {
1746
							that.close();
1747
						}
1748
 
1749
						return false;
1750
					}
1751
				});
1752
			}
1753
 
1754
			this.overlay.css( opts.css ).show();
1755
		},
1756
 
1757
		close : function() {
1758
			var scrollV, scrollH;
1759
 
1760
			W.unbind('resize.overlay');
1761
 
1762
			if (this.el.hasClass('fancybox-lock')) {
1763
				$('.fancybox-margin').removeClass('fancybox-margin');
1764
 
1765
				scrollV = W.scrollTop();
1766
				scrollH = W.scrollLeft();
1767
 
1768
				this.el.removeClass('fancybox-lock');
1769
 
1770
				W.scrollTop( scrollV ).scrollLeft( scrollH );
1771
			}
1772
 
1773
			$('.fancybox-overlay').remove().hide();
1774
 
1775
			$.extend(this, {
1776
				overlay : null,
1777
				fixed   : false
1778
			});
1779
		},
1780
 
1781
		// Private, callbacks
1782
 
1783
		update : function () {
1784
			var width = '100%', offsetWidth;
1785
 
1786
			// Reset width/height so it will not mess
1787
			this.overlay.width(width).height('100%');
1788
 
1789
			// jQuery does not return reliable result for IE
1790
			if (IE) {
1791
				offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth);
1792
 
1793
				if (D.width() > offsetWidth) {
1794
					width = D.width();
1795
				}
1796
 
1797
			} else if (D.width() > W.width()) {
1798
				width = D.width();
1799
			}
1800
 
1801
			this.overlay.width(width).height(D.height());
1802
		},
1803
 
1804
		// This is where we can manipulate DOM, because later it would cause iframes to reload
1805
		onReady : function (opts, obj) {
1806
			var overlay = this.overlay;
1807
 
1808
			$('.fancybox-overlay').stop(true, true);
1809
 
1810
			if (!overlay) {
1811
				this.create(opts);
1812
			}
1813
 
1814
			if (opts.locked && this.fixed && obj.fixed) {
1815
				if (!overlay) {
1816
					this.margin = D.height() > W.height() ? $('html').css('margin-right').replace("px", "") : false;
1817
				}
1818
 
1819
				obj.locked = this.overlay.append( obj.wrap );
1820
				obj.fixed  = false;
1821
			}
1822
 
1823
			if (opts.showEarly === true) {
1824
				this.beforeShow.apply(this, arguments);
1825
			}
1826
		},
1827
 
1828
		beforeShow : function(opts, obj) {
1829
			var scrollV, scrollH;
1830
 
1831
			if (obj.locked) {
1832
				if (this.margin !== false) {
1833
					$('*').filter(function(){
1834
						return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap") );
1835
					}).addClass('fancybox-margin');
1836
 
1837
					this.el.addClass('fancybox-margin');
1838
				}
1839
 
1840
				scrollV = W.scrollTop();
1841
				scrollH = W.scrollLeft();
1842
 
1843
				this.el.addClass('fancybox-lock');
1844
 
1845
				W.scrollTop( scrollV ).scrollLeft( scrollH );
1846
			}
1847
 
1848
			this.open(opts);
1849
		},
1850
 
1851
		onUpdate : function() {
1852
			if (!this.fixed) {
1853
				this.update();
1854
			}
1855
		},
1856
 
1857
		afterClose: function (opts) {
1858
			// Remove overlay if exists and fancyBox is not opening
1859
			// (e.g., it is not being open using afterClose callback)
1860
			//if (this.overlay && !F.isActive) {
1861
			if (this.overlay && !F.coming) {
1862
				this.overlay.fadeOut(opts.speedOut, $.proxy( this.close, this ));
1863
			}
1864
		}
1865
	};
1866
 
1867
	/*
1868
	 *	Title helper
1869
	 */
1870
 
1871
	F.helpers.title = {
1872
		defaults : {
1873
			type     : 'float', // 'float', 'inside', 'outside' or 'over',
1874
			position : 'bottom' // 'top' or 'bottom'
1875
		},
1876
 
1877
		beforeShow: function (opts) {
1878
			var current = F.current,
1879
				text    = current.title,
1880
				type    = opts.type,
1881
				title,
1882
				target;
1883
 
1884
			if ($.isFunction(text)) {
1885
				text = text.call(current.element, current);
1886
			}
1887
 
1888
			if (!isString(text) || $.trim(text) === '') {
1889
				return;
1890
			}
1891
 
1892
			title = $('<div class="fancybox-title fancybox-title-' + type + '-wrap">' + text + '</div>');
1893
 
1894
			switch (type) {
1895
				case 'inside':
1896
					target = F.skin;
1897
				break;
1898
 
1899
				case 'outside':
1900
					target = F.wrap;
1901
				break;
1902
 
1903
				case 'over':
1904
					target = F.inner;
1905
				break;
1906
 
1907
				default: // 'float'
1908
					target = F.skin;
1909
 
1910
					title.appendTo('body');
1911
 
1912
					if (IE) {
1913
						title.width( title.width() );
1914
					}
1915
 
1916
					title.wrapInner('<span class="child"></span>');
1917
 
1918
					//Increase bottom margin so this title will also fit into viewport
1919
					F.current.margin[2] += Math.abs( getScalar(title.css('margin-bottom')) );
1920
				break;
1921
			}
1922
 
1923
			title[ (opts.position === 'top' ? 'prependTo'  : 'appendTo') ](target);
1924
		}
1925
	};
1926
 
1927
	// jQuery plugin initialization
1928
	$.fn.fancybox = function (options) {
1929
		var index,
1930
			that     = $(this),
1931
			selector = this.selector || '',
1932
			run      = function(e) {
1933
				var what = $(this).blur(), idx = index, relType, relVal;
1934
 
1935
				if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) {
1936
					relType = options.groupAttr || 'data-fancybox-group';
1937
					relVal  = what.attr(relType);
1938
 
1939
					if (!relVal) {
1940
						relType = 'rel';
1941
						relVal  = what.get(0)[ relType ];
1942
					}
1943
 
1944
					if (relVal && relVal !== '' && relVal !== 'nofollow') {
1945
						what = selector.length ? $(selector) : that;
1946
						what = what.filter('[' + relType + '="' + relVal + '"]');
1947
						idx  = what.index(this);
1948
					}
1949
 
1950
					options.index = idx;
1951
 
1952
					// Stop an event from bubbling if everything is fine
1953
					if (F.open(what, options) !== false) {
1954
						e.preventDefault();
1955
					}
1956
				}
1957
			};
1958
 
1959
		options = options || {};
1960
		index   = options.index || 0;
1961
 
1962
		if (!selector || options.live === false) {
1963
			that.unbind('click.fb-start').bind('click.fb-start', run);
1964
 
1965
		} else {
1966
			D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run);
1967
		}
1968
 
1969
		this.filter('[data-fancybox-start=1]').trigger('click');
1970
 
1971
		return this;
1972
	};
1973
 
1974
	// Tests that need a body at doc ready
1975
	D.ready(function() {
1976
		var w1, w2;
1977
 
1978
		if ( $.scrollbarWidth === undefined ) {
1979
			// http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth
1980
			$.scrollbarWidth = function() {
1981
				var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'),
1982
					child  = parent.children(),
1983
					width  = child.innerWidth() - child.height( 99 ).innerWidth();
1984
 
1985
				parent.remove();
1986
 
1987
				return width;
1988
			};
1989
		}
1990
 
1991
		if ( $.support.fixedPosition === undefined ) {
1992
			$.support.fixedPosition = (function() {
1993
				var elem  = $('<div style="position:fixed;top:20px;"></div>').appendTo('body'),
1994
					fixed = ( elem[0].offsetTop === 20 || elem[0].offsetTop === 15 );
1995
 
1996
				elem.remove();
1997
 
1998
				return fixed;
1999
			}());
2000
		}
2001
 
2002
		$.extend(F.defaults, {
2003
			scrollbarWidth : $.scrollbarWidth(),
2004
			fixed  : $.support.fixedPosition,
2005
			parent : $('body')
2006
		});
2007
 
2008
		//Get real width of page scroll-bar
2009
		w1 = $(window).width();
2010
 
2011
		H.addClass('fancybox-lock-test');
2012
 
2013
		w2 = $(window).width();
2014
 
2015
		H.removeClass('fancybox-lock-test');
2016
 
2017
		$("<style type='text/css'>.fancybox-margin{margin-right:" + (w2 - w1) + "px;}</style>").appendTo("head");
2018
	});
2019
 
2020
}(window, document, jQuery));