Completed
Push — master ( 8d2de8...1ce70a )
by Litera
17s
created

www/js/colorbox/jquery.colorbox.js   F

Complexity

Total Complexity 223
Complexity/F 3.01

Size

Lines of Code 1100
Function Count 74

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1100
c 0
b 0
f 0
cc 0
nc 0
rs 2.4
wmc 223
mnd 7
bc 177
fnc 74
bpm 2.3918
cpm 3.0135
noi 5

36 Functions

Rating   Name   Duplication   Size   Complexity  
A defaults.href 0 4 1
A publicMethod.remove 0 15 2
A jquery.colorbox.js ➔ start 0 12 1
A jquery.colorbox.js ➔ winheight 0 3 2
F jquery.colorbox.js ➔ load 0 126 16
A jquery.colorbox.js ➔ set 0 6 3
A jquery.colorbox.js ➔ clear 0 3 1
B jquery.colorbox.js ➔ appendHTML 0 50 5
A defaults.createIframe 0 21 4
A jquery.colorbox.js ➔ trapFocus 0 6 4
A jquery.colorbox.js ➔ getIndex 0 7 2
B jquery.colorbox.js ➔ $[colorbox] 0 37 6
B publicMethod.close 0 24 3
A defaults.rel 0 3 1
A jquery.colorbox.js ➔ retinaUrl 0 3 3
D publicMethod.position 0 100 8
F publicMethod.resize 0 39 10
A jquery.colorbox.js ➔ reset 0 9 1
A jquery.colorbox.js ➔ stop 0 17 1
A jquery.colorbox.js ➔ $tag 0 13 3
A publicMethod.element 0 3 1
D jquery.colorbox.js ➔ launch 0 84 11
B slideshow.constructor 0 79 1
A jquery.colorbox.js ➔ setClass 0 6 2
B jquery.colorbox.js ➔ slideshow 0 19 6
A defaults.createImg 0 12 2
A jquery.colorbox.js ➔ setSize 0 3 3
B publicMethod.next 0 6 5
B jquery.colorbox.js ➔ addBindings 0 62 4
A jquery.colorbox.js ➔ isImage 0 3 1
A jquery.colorbox.js ➔ trigger 0 6 1
B publicMethod.prep 0 133 5
B publicMethod.prev 0 6 5
B jquery.colorbox.js ➔ getRelated 0 20 5
A defaults.title 0 3 1
B jquery.colorbox.js ➔ Settings 0 31 2

How to fix   Complexity   

Complexity

Complex classes like www/js/colorbox/jquery.colorbox.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*!
2
	Colorbox 1.6.4
3
	license: MIT
4
	http://www.jacklmoore.com/colorbox
5
*/
6
(function ($, document, window) {
7
	var
8
	// Default settings object.
9
	// See http://jacklmoore.com/colorbox for details.
10
	defaults = {
11
		// data sources
12
		html: false,
13
		photo: false,
14
		iframe: false,
15
		inline: false,
16
17
		// behavior and appearance
18
		transition: "elastic",
19
		speed: 300,
20
		fadeOut: 300,
21
		width: false,
22
		initialWidth: "600",
23
		innerWidth: false,
24
		maxWidth: false,
25
		height: false,
26
		initialHeight: "450",
27
		innerHeight: false,
28
		maxHeight: false,
29
		scalePhotos: true,
30
		scrolling: true,
31
		opacity: 0.9,
32
		preloading: true,
33
		className: false,
34
		overlayClose: true,
35
		escKey: true,
36
		arrowKey: true,
37
		top: false,
38
		bottom: false,
39
		left: false,
40
		right: false,
41
		fixed: false,
42
		data: undefined,
43
		closeButton: true,
44
		fastIframe: true,
45
		open: false,
46
		reposition: true,
47
		loop: true,
48
		slideshow: false,
49
		slideshowAuto: true,
50
		slideshowSpeed: 2500,
51
		slideshowStart: "start slideshow",
52
		slideshowStop: "stop slideshow",
53
		photoRegex: /\.(gif|png|jp(e|g|eg)|bmp|ico|webp|jxr|svg)((#|\?).*)?$/i,
54
55
		// alternate image paths for high-res displays
56
		retinaImage: false,
57
		retinaUrl: false,
58
		retinaSuffix: '@2x.$1',
59
60
		// internationalization
61
		current: "image {current} of {total}",
62
		previous: "previous",
63
		next: "next",
64
		close: "close",
65
		xhrError: "This content failed to load.",
66
		imgError: "This image failed to load.",
67
68
		// accessbility
69
		returnFocus: true,
70
		trapFocus: true,
71
72
		// callbacks
73
		onOpen: false,
74
		onLoad: false,
75
		onComplete: false,
76
		onCleanup: false,
77
		onClosed: false,
78
79
		rel: function() {
80
			return this.rel;
81
		},
82
		href: function() {
83
			// using this.href would give the absolute url, when the href may have been inteded as a selector (e.g. '#container')
84
			return $(this).attr('href');
85
		},
86
		title: function() {
87
			return this.title;
88
		},
89
		createImg: function() {
90
			var img = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
91
			var attrs = $(this).data('cbox-img-attrs');
92
93
			if (typeof attrs === 'object') {
94
				$.each(attrs, function(key, val){
95
					img[key] = val;
96
				});
97
			}
98
99
			return img;
100
		},
101
		createIframe: function() {
102
			var iframe = document.createElement('iframe');
103
			var attrs = $(this).data('cbox-iframe-attrs');
104
105
			if (typeof attrs === 'object') {
106
				$.each(attrs, function(key, val){
107
					iframe[key] = val;
108
				});
109
			}
110
111
			if ('frameBorder' in iframe) {
112
				iframe.frameBorder = 0;
113
			}
114
			if ('allowTransparency' in iframe) {
115
				iframe.allowTransparency = "true";
116
			}
117
			iframe.name = (new Date()).getTime(); // give the iframe a unique name to prevent caching
118
			iframe.allowFullscreen = true;
119
120
			return iframe;
121
		}
122
	},
123
124
	// Abstracting the HTML and event identifiers for easy rebranding
125
	colorbox = 'colorbox',
126
	prefix = 'cbox',
127
	boxElement = prefix + 'Element',
128
129
	// Events
130
	event_open = prefix + '_open',
131
	event_load = prefix + '_load',
132
	event_complete = prefix + '_complete',
133
	event_cleanup = prefix + '_cleanup',
134
	event_closed = prefix + '_closed',
135
	event_purge = prefix + '_purge',
136
137
	// Cached jQuery Object Variables
138
	$overlay,
139
	$box,
140
	$wrap,
141
	$content,
142
	$topBorder,
143
	$leftBorder,
144
	$rightBorder,
145
	$bottomBorder,
146
	$related,
147
	$window,
148
	$loaded,
149
	$loadingBay,
150
	$loadingOverlay,
151
	$title,
152
	$current,
153
	$slideshow,
154
	$next,
155
	$prev,
156
	$close,
157
	$groupControls,
158
	$events = $('<a/>'), // $({}) would be preferred, but there is an issue with jQuery 1.4.2
159
160
	// Variables for cached values or use across multiple functions
161
	settings,
162
	interfaceHeight,
163
	interfaceWidth,
164
	loadedHeight,
165
	loadedWidth,
166
	index,
167
	photo,
168
	open,
169
	active,
170
	closing,
171
	loadingTimer,
172
	publicMethod,
173
	div = "div",
174
	requests = 0,
175
	previousCSS = {},
176
	init;
177
178
	// ****************
179
	// HELPER FUNCTIONS
180
	// ****************
181
182
	// Convenience function for creating new jQuery objects
183
	function $tag(tag, id, css) {
184
		var element = document.createElement(tag);
185
186
		if (id) {
187
			element.id = prefix + id;
188
		}
189
190
		if (css) {
191
			element.style.cssText = css;
192
		}
193
194
		return $(element);
195
	}
196
197
	// Get the window height using innerHeight when available to avoid an issue with iOS
198
	// http://bugs.jquery.com/ticket/6724
199
	function winheight() {
200
		return window.innerHeight ? window.innerHeight : $(window).height();
201
	}
202
203
	function Settings(element, options) {
204
		if (options !== Object(options)) {
205
			options = {};
206
		}
207
208
		this.cache = {};
209
		this.el = element;
210
211
		this.value = function(key) {
212
			var dataAttr;
213
214
			if (this.cache[key] === undefined) {
215
				dataAttr = $(this.el).attr('data-cbox-'+key);
216
217
				if (dataAttr !== undefined) {
218
					this.cache[key] = dataAttr;
219
				} else if (options[key] !== undefined) {
220
					this.cache[key] = options[key];
221
				} else if (defaults[key] !== undefined) {
222
					this.cache[key] = defaults[key];
223
				}
224
			}
225
226
			return this.cache[key];
227
		};
228
229
		this.get = function(key) {
230
			var value = this.value(key);
231
			return $.isFunction(value) ? value.call(this.el, this) : value;
232
		};
233
	}
234
235
	// Determine the next and previous members in a group.
236
	function getIndex(increment) {
237
		var
238
		max = $related.length,
239
		newIndex = (index + increment) % max;
240
241
		return (newIndex < 0) ? max + newIndex : newIndex;
242
	}
243
244
	// Convert '%' and 'px' values to integers
245
	function setSize(size, dimension) {
246
		return Math.round((/%/.test(size) ? ((dimension === 'x' ? $window.width() : winheight()) / 100) : 1) * parseInt(size, 10));
247
	}
248
249
	// Checks an href to see if it is a photo.
250
	// There is a force photo option (photo: true) for hrefs that cannot be matched by the regex.
251
	function isImage(settings, url) {
252
		return settings.get('photo') || settings.get('photoRegex').test(url);
253
	}
254
255
	function retinaUrl(settings, url) {
256
		return settings.get('retinaUrl') && window.devicePixelRatio > 1 ? url.replace(settings.get('photoRegex'), settings.get('retinaSuffix')) : url;
257
	}
258
259
	function trapFocus(e) {
260
		if ('contains' in $box[0] && !$box[0].contains(e.target) && e.target !== $overlay[0]) {
261
			e.stopPropagation();
262
			$box.focus();
263
		}
264
	}
265
266
	function setClass(str) {
267
		if (setClass.str !== str) {
268
			$box.add($overlay).removeClass(setClass.str).addClass(str);
269
			setClass.str = str;
270
		}
271
	}
272
273
	function getRelated(rel) {
274
		index = 0;
275
276
		if (rel && rel !== false && rel !== 'nofollow') {
277
			$related = $('.' + boxElement).filter(function () {
278
				var options = $.data(this, colorbox);
279
				var settings = new Settings(this, options);
280
				return (settings.get('rel') === rel);
281
			});
282
			index = $related.index(settings.el);
283
284
			// Check direct calls to Colorbox.
285
			if (index === -1) {
286
				$related = $related.add(settings.el);
287
				index = $related.length - 1;
288
			}
289
		} else {
290
			$related = $(settings.el);
291
		}
292
	}
293
294
	function trigger(event) {
295
		// for external use
296
		$(document).trigger(event);
297
		// for internal use
298
		$events.triggerHandler(event);
299
	}
300
301
	var slideshow = (function(){
302
		var active,
303
			className = prefix + "Slideshow_",
304
			click = "click." + prefix,
305
			timeOut;
306
307
		function clear () {
308
			clearTimeout(timeOut);
309
		}
310
311
		function set() {
312
			if (settings.get('loop') || $related[index + 1]) {
313
				clear();
314
				timeOut = setTimeout(publicMethod.next, settings.get('slideshowSpeed'));
315
			}
316
		}
317
318
		function start() {
319
			$slideshow
320
				.html(settings.get('slideshowStop'))
321
				.unbind(click)
322
				.one(click, stop);
323
324
			$events
325
				.bind(event_complete, set)
326
				.bind(event_load, clear);
327
328
			$box.removeClass(className + "off").addClass(className + "on");
329
		}
330
331
		function stop() {
332
			clear();
333
334
			$events
335
				.unbind(event_complete, set)
336
				.unbind(event_load, clear);
337
338
			$slideshow
339
				.html(settings.get('slideshowStart'))
340
				.unbind(click)
341
				.one(click, function () {
342
					publicMethod.next();
343
					start();
344
				});
345
346
			$box.removeClass(className + "on").addClass(className + "off");
347
		}
348
349
		function reset() {
350
			active = false;
351
			$slideshow.hide();
352
			clear();
353
			$events
354
				.unbind(event_complete, set)
355
				.unbind(event_load, clear);
356
			$box.removeClass(className + "off " + className + "on");
357
		}
358
359
		return function(){
360
			if (active) {
361
				if (!settings.get('slideshow')) {
362
					$events.unbind(event_cleanup, reset);
363
					reset();
364
				}
365
			} else {
366
				if (settings.get('slideshow') && $related[1]) {
367
					active = true;
368
					$events.one(event_cleanup, reset);
369
					if (settings.get('slideshowAuto')) {
370
						start();
371
					} else {
372
						stop();
373
					}
374
					$slideshow.show();
375
				}
376
			}
377
		};
378
379
	}());
380
381
382
	function launch(element) {
383
		var options;
384
385
		if (!closing) {
386
387
			options = $(element).data(colorbox);
388
389
			settings = new Settings(element, options);
390
391
			getRelated(settings.get('rel'));
392
393
			if (!open) {
394
				open = active = true; // Prevents the page-change action from queuing up if the visitor holds down the left or right keys.
395
396
				setClass(settings.get('className'));
397
398
				// Show colorbox so the sizes can be calculated in older versions of jQuery
399
				$box.css({visibility:'hidden', display:'block', opacity:''});
400
401
				$loaded = $tag(div, 'LoadedContent', 'width:0; height:0; overflow:hidden; visibility:hidden');
402
				$content.css({width:'', height:''}).append($loaded);
403
404
				// Cache values needed for size calculations
405
				interfaceHeight = $topBorder.height() + $bottomBorder.height() + $content.outerHeight(true) - $content.height();
406
				interfaceWidth = $leftBorder.width() + $rightBorder.width() + $content.outerWidth(true) - $content.width();
407
				loadedHeight = $loaded.outerHeight(true);
408
				loadedWidth = $loaded.outerWidth(true);
409
410
				// Opens inital empty Colorbox prior to content being loaded.
411
				var initialWidth = setSize(settings.get('initialWidth'), 'x');
412
				var initialHeight = setSize(settings.get('initialHeight'), 'y');
413
				var maxWidth = settings.get('maxWidth');
414
				var maxHeight = settings.get('maxHeight');
415
416
				settings.w = Math.max((maxWidth !== false ? Math.min(initialWidth, setSize(maxWidth, 'x')) : initialWidth) - loadedWidth - interfaceWidth, 0);
417
				settings.h = Math.max((maxHeight !== false ? Math.min(initialHeight, setSize(maxHeight, 'y')) : initialHeight) - loadedHeight - interfaceHeight, 0);
418
419
				$loaded.css({width:'', height:settings.h});
420
				publicMethod.position();
421
422
				trigger(event_open);
423
				settings.get('onOpen');
424
425
				$groupControls.add($title).hide();
426
427
				$box.focus();
428
429
				if (settings.get('trapFocus')) {
430
					// Confine focus to the modal
431
					// Uses event capturing that is not supported in IE8-
432
					if (document.addEventListener) {
433
434
						document.addEventListener('focus', trapFocus, true);
435
436
						$events.one(event_closed, function () {
437
							document.removeEventListener('focus', trapFocus, true);
438
						});
439
					}
440
				}
441
442
				// Return focus on closing
443
				if (settings.get('returnFocus')) {
444
					$events.one(event_closed, function () {
445
						$(settings.el).focus();
446
					});
447
				}
448
			}
449
450
			var opacity = parseFloat(settings.get('opacity'));
451
			$overlay.css({
452
				opacity: opacity === opacity ? opacity : '',
453
				cursor: settings.get('overlayClose') ? 'pointer' : '',
454
				visibility: 'visible'
455
			}).show();
456
457
			if (settings.get('closeButton')) {
458
				$close.html(settings.get('close')).appendTo($content);
459
			} else {
460
				$close.appendTo('<div/>'); // replace with .detach() when dropping jQuery < 1.4
461
			}
462
463
			load();
464
		}
465
	}
466
467
	// Colorbox's markup needs to be added to the DOM prior to being called
468
	// so that the browser will go ahead and load the CSS background images.
469
	function appendHTML() {
470
		if (!$box) {
471
			init = false;
472
			$window = $(window);
473
			$box = $tag(div).attr({
474
				id: colorbox,
475
				'class': $.support.opacity === false ? prefix + 'IE' : '', // class for optional IE8 & lower targeted CSS.
476
				role: 'dialog',
477
				tabindex: '-1'
478
			}).hide();
479
			$overlay = $tag(div, "Overlay").hide();
480
			$loadingOverlay = $([$tag(div, "LoadingOverlay")[0],$tag(div, "LoadingGraphic")[0]]);
481
			$wrap = $tag(div, "Wrapper");
482
			$content = $tag(div, "Content").append(
483
				$title = $tag(div, "Title"),
484
				$current = $tag(div, "Current"),
485
				$prev = $('<button type="button"/>').attr({id:prefix+'Previous'}),
486
				$next = $('<button type="button"/>').attr({id:prefix+'Next'}),
487
				$slideshow = $('<button type="button"/>').attr({id:prefix+'Slideshow'}),
488
				$loadingOverlay
489
			);
490
491
			$close = $('<button type="button"/>').attr({id:prefix+'Close'});
492
493
			$wrap.append( // The 3x3 Grid that makes up Colorbox
494
				$tag(div).append(
495
					$tag(div, "TopLeft"),
496
					$topBorder = $tag(div, "TopCenter"),
497
					$tag(div, "TopRight")
498
				),
499
				$tag(div, false, 'clear:left').append(
500
					$leftBorder = $tag(div, "MiddleLeft"),
501
					$content,
502
					$rightBorder = $tag(div, "MiddleRight")
503
				),
504
				$tag(div, false, 'clear:left').append(
505
					$tag(div, "BottomLeft"),
506
					$bottomBorder = $tag(div, "BottomCenter"),
507
					$tag(div, "BottomRight")
508
				)
509
			).find('div div').css({'float': 'left'});
510
511
			$loadingBay = $tag(div, false, 'position:absolute; width:9999px; visibility:hidden; display:none; max-width:none;');
512
513
			$groupControls = $next.add($prev).add($current).add($slideshow);
514
		}
515
		if (document.body && !$box.parent().length) {
516
			$(document.body).append($overlay, $box.append($wrap, $loadingBay));
0 ignored issues
show
Bug introduced by
The variable $overlay does not seem to be initialized in case !$box on line 470 is false. Are you sure the function append handles undefined variables?
Loading history...
Bug introduced by
The variable $loadingBay does not seem to be initialized in case !$box on line 470 is false. Are you sure the function append handles undefined variables?
Loading history...
Bug introduced by
The variable $wrap does not seem to be initialized in case !$box on line 470 is false. Are you sure the function append handles undefined variables?
Loading history...
517
		}
518
	}
519
520
	// Add Colorbox's event bindings
521
	function addBindings() {
522
		function clickHandler(e) {
523
			// ignore non-left-mouse-clicks and clicks modified with ctrl / command, shift, or alt.
524
			// See: http://jacklmoore.com/notes/click-events/
525
			if (!(e.which > 1 || e.shiftKey || e.altKey || e.metaKey || e.ctrlKey)) {
526
				e.preventDefault();
527
				launch(this);
528
			}
529
		}
530
531
		if ($box) {
532
			if (!init) {
533
				init = true;
534
535
				// Anonymous functions here keep the public method from being cached, thereby allowing them to be redefined on the fly.
536
				$next.click(function () {
537
					publicMethod.next();
538
				});
539
				$prev.click(function () {
540
					publicMethod.prev();
541
				});
542
				$close.click(function () {
543
					publicMethod.close();
544
				});
545
				$overlay.click(function () {
546
					if (settings.get('overlayClose')) {
547
						publicMethod.close();
548
					}
549
				});
550
551
				// Key Bindings
552
				$(document).bind('keydown.' + prefix, function (e) {
553
					var key = e.keyCode;
554
					if (open && settings.get('escKey') && key === 27) {
555
						e.preventDefault();
556
						publicMethod.close();
557
					}
558
					if (open && settings.get('arrowKey') && $related[1] && !e.altKey) {
559
						if (key === 37) {
560
							e.preventDefault();
561
							$prev.click();
562
						} else if (key === 39) {
563
							e.preventDefault();
564
							$next.click();
565
						}
566
					}
567
				});
568
569
				if ($.isFunction($.fn.on)) {
570
					// For jQuery 1.7+
571
					$(document).on('click.'+prefix, '.'+boxElement, clickHandler);
572
				} else {
573
					// For jQuery 1.3.x -> 1.6.x
574
					// This code is never reached in jQuery 1.9, so do not contact me about 'live' being removed.
575
					// This is not here for jQuery 1.9, it's here for legacy users.
576
					$('.'+boxElement).live('click.'+prefix, clickHandler);
577
				}
578
			}
579
			return true;
580
		}
581
		return false;
582
	}
583
584
	// Don't do anything if Colorbox already exists.
585
	if ($[colorbox]) {
586
		return;
587
	}
588
589
	// Append the HTML when the DOM loads
590
	$(appendHTML);
591
592
593
	// ****************
594
	// PUBLIC FUNCTIONS
595
	// Usage format: $.colorbox.close();
596
	// Usage from within an iframe: parent.jQuery.colorbox.close();
597
	// ****************
598
599
	publicMethod = $.fn[colorbox] = $[colorbox] = function (options, callback) {
600
		var settings;
601
		var $obj = this;
602
603
		options = options || {};
604
605
		if ($.isFunction($obj)) { // assume a call to $.colorbox
606
			$obj = $('<a/>');
607
			options.open = true;
608
		}
609
610
		if (!$obj[0]) { // colorbox being applied to empty collection
611
			return $obj;
612
		}
613
614
		appendHTML();
615
616
		if (addBindings()) {
617
618
			if (callback) {
619
				options.onComplete = callback;
620
			}
621
622
			$obj.each(function () {
623
				var old = $.data(this, colorbox) || {};
624
				$.data(this, colorbox, $.extend(old, options));
625
			}).addClass(boxElement);
626
627
			settings = new Settings($obj[0], options);
628
629
			if (settings.get('open')) {
630
				launch($obj[0]);
631
			}
632
		}
633
634
		return $obj;
635
	};
636
637
	publicMethod.position = function (speed, loadedCallback) {
638
		var
639
		css,
640
		top = 0,
641
		left = 0,
642
		offset = $box.offset(),
643
		scrollTop,
644
		scrollLeft;
645
646
		$window.unbind('resize.' + prefix);
647
648
		// remove the modal so that it doesn't influence the document width/height
649
		$box.css({top: -9e4, left: -9e4});
650
651
		scrollTop = $window.scrollTop();
652
		scrollLeft = $window.scrollLeft();
653
654
		if (settings.get('fixed')) {
655
			offset.top -= scrollTop;
656
			offset.left -= scrollLeft;
657
			$box.css({position: 'fixed'});
658
		} else {
659
			top = scrollTop;
660
			left = scrollLeft;
661
			$box.css({position: 'absolute'});
662
		}
663
664
		// keeps the top and left positions within the browser's viewport.
665
		if (settings.get('right') !== false) {
666
			left += Math.max($window.width() - settings.w - loadedWidth - interfaceWidth - setSize(settings.get('right'), 'x'), 0);
667
		} else if (settings.get('left') !== false) {
668
			left += setSize(settings.get('left'), 'x');
669
		} else {
670
			left += Math.round(Math.max($window.width() - settings.w - loadedWidth - interfaceWidth, 0) / 2);
671
		}
672
673
		if (settings.get('bottom') !== false) {
674
			top += Math.max(winheight() - settings.h - loadedHeight - interfaceHeight - setSize(settings.get('bottom'), 'y'), 0);
675
		} else if (settings.get('top') !== false) {
676
			top += setSize(settings.get('top'), 'y');
677
		} else {
678
			top += Math.round(Math.max(winheight() - settings.h - loadedHeight - interfaceHeight, 0) / 2);
679
		}
680
681
		$box.css({top: offset.top, left: offset.left, visibility:'visible'});
682
683
		// this gives the wrapper plenty of breathing room so it's floated contents can move around smoothly,
684
		// but it has to be shrank down around the size of div#colorbox when it's done.  If not,
685
		// it can invoke an obscure IE bug when using iframes.
686
		$wrap[0].style.width = $wrap[0].style.height = "9999px";
687
688
		function modalDimensions() {
689
			$topBorder[0].style.width = $bottomBorder[0].style.width = $content[0].style.width = (parseInt($box[0].style.width,10) - interfaceWidth)+'px';
690
			$content[0].style.height = $leftBorder[0].style.height = $rightBorder[0].style.height = (parseInt($box[0].style.height,10) - interfaceHeight)+'px';
691
		}
692
693
		css = {width: settings.w + loadedWidth + interfaceWidth, height: settings.h + loadedHeight + interfaceHeight, top: top, left: left};
694
695
		// setting the speed to 0 if the content hasn't changed size or position
696
		if (speed) {
697
			var tempSpeed = 0;
698
			$.each(css, function(i){
699
				if (css[i] !== previousCSS[i]) {
700
					tempSpeed = speed;
701
					return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
702
				}
703
			});
704
			speed = tempSpeed;
705
		}
706
707
		previousCSS = css;
708
709
		if (!speed) {
710
			$box.css(css);
711
		}
712
713
		$box.dequeue().animate(css, {
714
			duration: speed || 0,
715
			complete: function () {
716
				modalDimensions();
717
718
				active = false;
719
720
				// shrink the wrapper down to exactly the size of colorbox to avoid a bug in IE's iframe implementation.
721
				$wrap[0].style.width = (settings.w + loadedWidth + interfaceWidth) + "px";
722
				$wrap[0].style.height = (settings.h + loadedHeight + interfaceHeight) + "px";
723
724
				if (settings.get('reposition')) {
725
					setTimeout(function () {  // small delay before binding onresize due to an IE8 bug.
726
						$window.bind('resize.' + prefix, publicMethod.position);
727
					}, 1);
728
				}
729
730
				if ($.isFunction(loadedCallback)) {
731
					loadedCallback();
732
				}
733
			},
734
			step: modalDimensions
735
		});
736
	};
737
738
	publicMethod.resize = function (options) {
739
		var scrolltop;
740
741
		if (open) {
742
			options = options || {};
743
744
			if (options.width) {
745
				settings.w = setSize(options.width, 'x') - loadedWidth - interfaceWidth;
746
			}
747
748
			if (options.innerWidth) {
749
				settings.w = setSize(options.innerWidth, 'x');
750
			}
751
752
			$loaded.css({width: settings.w});
753
754
			if (options.height) {
755
				settings.h = setSize(options.height, 'y') - loadedHeight - interfaceHeight;
756
			}
757
758
			if (options.innerHeight) {
759
				settings.h = setSize(options.innerHeight, 'y');
760
			}
761
762
			if (!options.innerHeight && !options.height) {
763
				scrolltop = $loaded.scrollTop();
764
				$loaded.css({height: "auto"});
765
				settings.h = $loaded.height();
766
			}
767
768
			$loaded.css({height: settings.h});
769
770
			if(scrolltop) {
771
				$loaded.scrollTop(scrolltop);
772
			}
773
774
			publicMethod.position(settings.get('transition') === "none" ? 0 : settings.get('speed'));
775
		}
776
	};
777
778
	publicMethod.prep = function (object) {
779
		if (!open) {
780
			return;
781
		}
782
783
		var callback, speed = settings.get('transition') === "none" ? 0 : settings.get('speed');
784
785
		$loaded.remove();
786
787
		$loaded = $tag(div, 'LoadedContent').append(object);
788
789
		function getWidth() {
790
			settings.w = settings.w || $loaded.width();
791
			settings.w = settings.mw && settings.mw < settings.w ? settings.mw : settings.w;
792
			return settings.w;
793
		}
794
		function getHeight() {
795
			settings.h = settings.h || $loaded.height();
796
			settings.h = settings.mh && settings.mh < settings.h ? settings.mh : settings.h;
797
			return settings.h;
798
		}
799
800
		$loaded.hide()
801
		.appendTo($loadingBay.show())// content has to be appended to the DOM for accurate size calculations.
802
		.css({width: getWidth(), overflow: settings.get('scrolling') ? 'auto' : 'hidden'})
803
		.css({height: getHeight()})// sets the height independently from the width in case the new width influences the value of height.
804
		.prependTo($content);
805
806
		$loadingBay.hide();
807
808
		// floating the IMG removes the bottom line-height and fixed a problem where IE miscalculates the width of the parent element as 100% of the document width.
809
810
		$(photo).css({'float': 'none'});
811
812
		setClass(settings.get('className'));
813
814
		callback = function () {
815
			var total = $related.length,
816
				iframe,
817
				complete;
818
819
			if (!open) {
820
				return;
821
			}
822
823
			function removeFilter() { // Needed for IE8 in versions of jQuery prior to 1.7.2
824
				if ($.support.opacity === false) {
825
					$box[0].style.removeAttribute('filter');
826
				}
827
			}
828
829
			complete = function () {
830
				clearTimeout(loadingTimer);
831
				$loadingOverlay.hide();
832
				trigger(event_complete);
833
				settings.get('onComplete');
834
			};
835
836
837
			$title.html(settings.get('title')).show();
838
			$loaded.show();
839
840
			if (total > 1) { // handle grouping
841
				if (typeof settings.get('current') === "string") {
842
					$current.html(settings.get('current').replace('{current}', index + 1).replace('{total}', total)).show();
843
				}
844
845
				$next[(settings.get('loop') || index < total - 1) ? "show" : "hide"]().html(settings.get('next'));
846
				$prev[(settings.get('loop') || index) ? "show" : "hide"]().html(settings.get('previous'));
847
848
				slideshow();
849
850
				// Preloads images within a rel group
851
				if (settings.get('preloading')) {
852
					$.each([getIndex(-1), getIndex(1)], function(){
853
						var img,
854
							i = $related[this],
855
							settings = new Settings(i, $.data(i, colorbox)),
856
							src = settings.get('href');
857
858
						if (src && isImage(settings, src)) {
859
							src = retinaUrl(settings, src);
860
							img = document.createElement('img');
861
							img.src = src;
862
						}
863
					});
864
				}
865
			} else {
866
				$groupControls.hide();
867
			}
868
869
			if (settings.get('iframe')) {
870
871
				iframe = settings.get('createIframe');
872
873
				if (!settings.get('scrolling')) {
874
					iframe.scrolling = "no";
875
				}
876
877
				$(iframe)
878
					.attr({
879
						src: settings.get('href'),
880
						'class': prefix + 'Iframe'
881
					})
882
					.one('load', complete)
883
					.appendTo($loaded);
884
885
				$events.one(event_purge, function () {
886
					iframe.src = "//about:blank";
887
				});
888
889
				if (settings.get('fastIframe')) {
890
					$(iframe).trigger('load');
891
				}
892
			} else {
893
				complete();
894
			}
895
896
			if (settings.get('transition') === 'fade') {
897
				$box.fadeTo(speed, 1, removeFilter);
898
			} else {
899
				removeFilter();
900
			}
901
		};
902
903
		if (settings.get('transition') === 'fade') {
904
			$box.fadeTo(speed, 0, function () {
905
				publicMethod.position(0, callback);
906
			});
907
		} else {
908
			publicMethod.position(speed, callback);
909
		}
910
	};
911
912
	function load () {
913
		var href, setResize, prep = publicMethod.prep, $inline, request = ++requests;
914
915
		active = true;
916
917
		photo = false;
918
919
		trigger(event_purge);
920
		trigger(event_load);
921
		settings.get('onLoad');
922
923
		settings.h = settings.get('height') ?
924
				setSize(settings.get('height'), 'y') - loadedHeight - interfaceHeight :
925
				settings.get('innerHeight') && setSize(settings.get('innerHeight'), 'y');
926
927
		settings.w = settings.get('width') ?
928
				setSize(settings.get('width'), 'x') - loadedWidth - interfaceWidth :
929
				settings.get('innerWidth') && setSize(settings.get('innerWidth'), 'x');
930
931
		// Sets the minimum dimensions for use in image scaling
932
		settings.mw = settings.w;
933
		settings.mh = settings.h;
934
935
		// Re-evaluate the minimum width and height based on maxWidth and maxHeight values.
936
		// If the width or height exceed the maxWidth or maxHeight, use the maximum values instead.
937
		if (settings.get('maxWidth')) {
938
			settings.mw = setSize(settings.get('maxWidth'), 'x') - loadedWidth - interfaceWidth;
939
			settings.mw = settings.w && settings.w < settings.mw ? settings.w : settings.mw;
940
		}
941
		if (settings.get('maxHeight')) {
942
			settings.mh = setSize(settings.get('maxHeight'), 'y') - loadedHeight - interfaceHeight;
943
			settings.mh = settings.h && settings.h < settings.mh ? settings.h : settings.mh;
944
		}
945
946
		href = settings.get('href');
947
948
		loadingTimer = setTimeout(function () {
949
			$loadingOverlay.show();
950
		}, 100);
951
952
		if (settings.get('inline')) {
953
			var $target = $(href).eq(0);
954
			// Inserts an empty placeholder where inline content is being pulled from.
955
			// An event is bound to put inline content back when Colorbox closes or loads new content.
956
			$inline = $('<div>').hide().insertBefore($target);
957
958
			$events.one(event_purge, function () {
959
				$inline.replaceWith($target);
960
			});
961
962
			prep($target);
963
		} else if (settings.get('iframe')) {
964
			// IFrame element won't be added to the DOM until it is ready to be displayed,
965
			// to avoid problems with DOM-ready JS that might be trying to run in that iframe.
966
			prep(" ");
967
		} else if (settings.get('html')) {
968
			prep(settings.get('html'));
969
		} else if (isImage(settings, href)) {
970
971
			href = retinaUrl(settings, href);
972
973
			photo = settings.get('createImg');
974
975
			$(photo)
976
			.addClass(prefix + 'Photo')
977
			.bind('error.'+prefix,function () {
978
				prep($tag(div, 'Error').html(settings.get('imgError')));
979
			})
980
			.one('load', function () {
981
				if (request !== requests) {
982
					return;
983
				}
984
985
				// A small pause because some browsers will occasionally report a
986
				// img.width and img.height of zero immediately after the img.onload fires
987
				setTimeout(function(){
988
					var percent;
989
990
					if (settings.get('retinaImage') && window.devicePixelRatio > 1) {
991
						photo.height = photo.height / window.devicePixelRatio;
992
						photo.width = photo.width / window.devicePixelRatio;
993
					}
994
995
					if (settings.get('scalePhotos')) {
996
						setResize = function () {
997
							photo.height -= photo.height * percent;
998
							photo.width -= photo.width * percent;
999
						};
1000
						if (settings.mw && photo.width > settings.mw) {
1001
							percent = (photo.width - settings.mw) / photo.width;
1002
							setResize();
1003
						}
1004
						if (settings.mh && photo.height > settings.mh) {
1005
							percent = (photo.height - settings.mh) / photo.height;
1006
							setResize();
1007
						}
1008
					}
1009
1010
					if (settings.h) {
1011
						photo.style.marginTop = Math.max(settings.mh - photo.height, 0) / 2 + 'px';
1012
					}
1013
1014
					if ($related[1] && (settings.get('loop') || $related[index + 1])) {
1015
						photo.style.cursor = 'pointer';
1016
1017
						$(photo).bind('click.'+prefix, function () {
1018
							publicMethod.next();
1019
						});
1020
					}
1021
1022
					photo.style.width = photo.width + 'px';
1023
					photo.style.height = photo.height + 'px';
1024
					prep(photo);
1025
				}, 1);
1026
			});
1027
1028
			photo.src = href;
1029
1030
		} else if (href) {
1031
			$loadingBay.load(href, settings.get('data'), function (data, status) {
1032
				if (request === requests) {
1033
					prep(status === 'error' ? $tag(div, 'Error').html(settings.get('xhrError')) : $(this).contents());
1034
				}
1035
			});
1036
		}
1037
	}
1038
1039
	// Navigates to the next page/image in a set.
1040
	publicMethod.next = function () {
1041
		if (!active && $related[1] && (settings.get('loop') || $related[index + 1])) {
1042
			index = getIndex(1);
1043
			launch($related[index]);
1044
		}
1045
	};
1046
1047
	publicMethod.prev = function () {
1048
		if (!active && $related[1] && (settings.get('loop') || index)) {
1049
			index = getIndex(-1);
1050
			launch($related[index]);
1051
		}
1052
	};
1053
1054
	// Note: to use this within an iframe use the following format: parent.jQuery.colorbox.close();
1055
	publicMethod.close = function () {
1056
		if (open && !closing) {
1057
1058
			closing = true;
1059
			open = false;
1060
			trigger(event_cleanup);
1061
			settings.get('onCleanup');
1062
			$window.unbind('.' + prefix);
1063
			$overlay.fadeTo(settings.get('fadeOut') || 0, 0);
1064
1065
			$box.stop().fadeTo(settings.get('fadeOut') || 0, 0, function () {
1066
				$box.hide();
1067
				$overlay.hide();
1068
				trigger(event_purge);
1069
				$loaded.remove();
1070
1071
				setTimeout(function () {
1072
					closing = false;
1073
					trigger(event_closed);
1074
					settings.get('onClosed');
1075
				}, 1);
1076
			});
1077
		}
1078
	};
1079
1080
	// Removes changes Colorbox made to the document, but does not remove the plugin.
1081
	publicMethod.remove = function () {
1082
		if (!$box) { return; }
1083
1084
		$box.stop();
1085
		$[colorbox].close();
1086
		$box.stop(false, true).remove();
1087
		$overlay.remove();
1088
		closing = false;
1089
		$box = null;
1090
		$('.' + boxElement)
1091
			.removeData(colorbox)
1092
			.removeClass(boxElement);
1093
1094
		$(document).unbind('click.'+prefix).unbind('keydown.'+prefix);
1095
	};
1096
1097
	// A method for fetching the current element Colorbox is referencing.
1098
	// returns a jQuery object.
1099
	publicMethod.element = function () {
1100
		return $(settings.el);
1101
	};
1102
1103
	publicMethod.settings = defaults;
1104
1105
}(jQuery, document, window));
1106