PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.8
VikBooking Hotel Booking Engine & PMS v1.8.8
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / site / resources / jquery.fancybox.js

jquery.fancybox.js in VikBooking Hotel Booking Engine & PMS 1.8.8, at site/resources/jquery.fancybox.js

2,020 lines 47.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 - [email protected]
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));