Updated timepicker
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / js / 3rdParty / slimbox2.js
CommitLineData
4c51a0e9 1/*!
9e16745a
AE
2 Slimbox v2.05 - The ultimate lightweight Lightbox clone for jQuery
3 (c) 2007-2013 Christophe Beyls <http://www.digitalia.be>
4c51a0e9
AE
4 MIT-style license.
5
6 Modified by WoltLab GmbH to support large images.
7*/
8
9(function($) {
10
11 // Global variables, accessible to Slimbox only
12 var win = $(window), options, images, activeImage = -1, activeURL, prevImage, nextImage, compatibleOverlay, middle, centerWidth, centerHeight,
13 ie6 = !window.XMLHttpRequest, hiddenElements = [], documentElement = document.documentElement,
14
15 // Preload images
16 preload = {}, preloadPrev = new Image(), preloadNext = new Image(),
17
18 // DOM elements
19 overlay, center, image, sizer, prevLink, nextLink, bottomContainer, bottom, caption, number;
20
21 /*
22 Initialization
23 */
24
25 $(function() {
26 // Append the Slimbox HTML code at the bottom of the document
27 $("body").append(
28 $([
9e16745a 29 overlay = $('<div id="lbOverlay" />').click(close)[0],
4c51a0e9
AE
30 center = $('<div id="lbCenter" />')[0],
31 bottomContainer = $('<div id="lbBottomContainer" />')[0]
32 ]).css("display", "none")
33 );
34
35 image = $('<div id="lbImage" />').appendTo(center).append(
36 sizer = $('<div style="position: relative;" />').append([
37 prevLink = $('<a id="lbPrevLink" href="#" />').click(previous)[0],
38 nextLink = $('<a id="lbNextLink" href="#" />').click(next)[0]
39 ])[0]
40 )[0];
41
42 bottom = $('<div id="lbBottom" />').appendTo(bottomContainer).append([
9e16745a 43 $('<a id="lbCloseLink" href="#" />').click(close)[0],
4c51a0e9
AE
44 caption = $('<div id="lbCaption" />')[0],
45 number = $('<div id="lbNumber" />')[0],
46 $('<div style="clear: both;" />')[0]
47 ])[0];
48 });
49
50
51 /*
52 API
53 */
54
55 // Open Slimbox with the specified parameters
56 $.slimbox = function(_images, startImage, _options) {
57 options = $.extend({
58 loop: false, // Allows to navigate between first and last images
59 overlayOpacity: 0.8, // 1 is opaque, 0 is completely transparent (change the color in the CSS file)
60 overlayFadeDuration: 400, // Duration of the overlay fade-in and fade-out animations (in milliseconds)
61 resizeDuration: 400, // Duration of each of the box resize animations (in milliseconds)
62 resizeEasing: "swing", // "swing" is jQuery's default easing
63 initialWidth: 250, // Initial width of the box (in pixels)
64 initialHeight: 250, // Initial height of the box (in pixels)
65 imageFadeDuration: 400, // Duration of the image fade-in animation (in milliseconds)
66 captionAnimationDuration: 400, // Duration of the caption animation (in milliseconds)
67 counterText: "Image {x} of {y}", // Translate or change as you wish, or set it to false to disable counter text for image groups
68 closeKeys: [27, 88, 67], // Array of keycodes to close Slimbox, default: Esc (27), 'x' (88), 'c' (67)
69 previousKeys: [37, 80], // Array of keycodes to navigate to the previous image, default: Left arrow (37), 'p' (80)
70 nextKeys: [39, 78] // Array of keycodes to navigate to the next image, default: Right arrow (39), 'n' (78)
71 }, _options);
72
73 // The function is called for a single image, with URL and Title as first two arguments
74 if (typeof _images == "string") {
75 _images = [[_images, startImage]];
76 startImage = 0;
77 }
4d772854 78
c6771d73 79 // WoltLab modifications BEGIN
4d772854
TD
80 if (activeImage == -1) {
81 middle = win.scrollTop() + (win.height() / 2);
82 centerWidth = options.initialWidth;
83 centerHeight = options.initialHeight;
84 $(center).css({top: Math.max(0, middle - (centerHeight / 2)), width: centerWidth, height: centerHeight, marginLeft: -centerWidth/2}).show();
85 compatibleOverlay = ie6 || (overlay.currentStyle && (overlay.currentStyle.position != "fixed"));
86 if (compatibleOverlay) overlay.style.position = "absolute";
87 $(overlay).css("opacity", options.overlayOpacity).fadeIn(options.overlayFadeDuration);
c6771d73 88
4d772854 89 WCF.System.DisableScrolling.disable();
c6771d73 90
4d772854
TD
91 position();
92 setup(1);
93 }
c6771d73 94 // WoltLab modifications END
4d772854 95
4c51a0e9
AE
96 images = _images;
97 options.loop = options.loop && (images.length > 1);
98 return changeImage(startImage);
99 };
100
101 /*
102 options: Optional options object, see jQuery.slimbox()
103 linkMapper: Optional function taking a link DOM element and an index as arguments and returning an array containing 2 elements:
104 the image URL and the image caption (may contain HTML)
105 linksFilter: Optional function taking a link DOM element and an index as arguments and returning true if the element is part of
106 the image collection that will be shown on click, false if not. "this" refers to the element that was clicked.
107 This function must always return true when the DOM element argument is "this".
108 */
109 $.fn.slimbox = function(_options, linkMapper, linksFilter) {
110 linkMapper = linkMapper || function(el) {
111 return [el.href, el.title];
112 };
113
114 linksFilter = linksFilter || function() {
115 return true;
116 };
117
118 var links = this;
119
120 return links.unbind("click").click(function() {
121 // Build the list of images that will be displayed
122 var link = this, startIndex = 0, filteredLinks, i = 0, length;
123 filteredLinks = $.grep(links, function(el, i) {
124 return linksFilter.call(link, el, i);
125 });
126
127 // We cannot use jQuery.map() because it flattens the returned array
128 for (length = filteredLinks.length; i < length; ++i) {
129 if (filteredLinks[i] == link) startIndex = i;
130 filteredLinks[i] = linkMapper(filteredLinks[i], i);
131 }
132
133 return $.slimbox(filteredLinks, startIndex, _options);
134 });
135 };
136
137
138 /*
139 Internal functions
140 */
141
142 function position() {
143 var l = win.scrollLeft(), w = win.width();
144 $([center, bottomContainer]).css("left", l + (w / 2));
145 if (compatibleOverlay) $(overlay).css({left: l, top: win.scrollTop(), width: w, height: win.height()});
146 }
147
148 function setup(open) {
149 if (open) {
150 $("object").add(ie6 ? "select" : "embed").each(function(index, el) {
151 hiddenElements[index] = [el, el.style.visibility];
152 el.style.visibility = "hidden";
153 });
154 } else {
155 $.each(hiddenElements, function(index, el) {
156 el[0].style.visibility = el[1];
157 });
158 hiddenElements = [];
159 }
160 var fn = open ? "bind" : "unbind";
161 win[fn]("scroll resize", position);
162 $(document)[fn]("keydown", keyDown);
163 }
164
165 function keyDown(event) {
9e16745a 166 var code = event.which, fn = $.inArray;
4c51a0e9
AE
167 // Prevent default keyboard action (like navigating inside the page)
168 return (fn(code, options.closeKeys) >= 0) ? close()
169 : (fn(code, options.nextKeys) >= 0) ? next()
170 : (fn(code, options.previousKeys) >= 0) ? previous()
9e16745a 171 : null;
4c51a0e9
AE
172 }
173
174 function previous() {
175 return changeImage(prevImage);
176 }
177
178 function next() {
179 return changeImage(nextImage);
180 }
181
182 function changeImage(imageIndex) {
183 if (imageIndex >= 0) {
184 activeImage = imageIndex;
185 activeURL = images[activeImage][0];
186 prevImage = (activeImage || (options.loop ? images.length : 0)) - 1;
187 nextImage = ((activeImage + 1) % images.length) || (options.loop ? 0 : -1);
188
189 stop();
341b056c
AE
190 // WoltLab modifications BEGIN
191
c6771d73 192 // center.className = "lbLoading";
341b056c
AE
193 $('<span class="icon icon48 icon-spinner" />').appendTo(center);
194
195 // WoltLab modifications END
4c51a0e9
AE
196
197 preload = new Image();
198 preload.onload = animateBox;
199 preload.src = activeURL;
200 }
201
202 return false;
203 }
204
205 function animateBox() {
c6771d73
TD
206 // WoltLab modifications BEGIN
207
341b056c 208 //center.className = "";
c6771d73
TD
209
210 // WoltLab modifications END
4c51a0e9
AE
211 $(image).css({backgroundImage: "url(" + activeURL + ")", visibility: "hidden", display: ""});
212 $(sizer).width(preload.width);
213 $([sizer, prevLink, nextLink]).height(preload.height);
214
215 $(caption).html(images[activeImage][1] || "");
216 $(number).html((((images.length > 1) && options.counterText) || "").replace(/{x}/, activeImage + 1).replace(/{y}/, images.length));
217
218 if (prevImage >= 0) preloadPrev.src = images[prevImage][0];
219 if (nextImage >= 0) preloadNext.src = images[nextImage][0];
220
221 centerWidth = image.offsetWidth;
222 centerHeight = image.offsetHeight;
223
224 // WoltLab modifications BEGIN
225
226 // restrict maximum dimensions to 80% of page size
227 var $dimensions = $(window).getDimensions();
228 var $maxHeight = Math.round($dimensions.height * 0.8);
229 var $maxWidth = Math.round($dimensions.width * 0.8);
230 if (centerHeight > $maxHeight || centerWidth > $maxWidth) {
231 var $ratioHeight = $maxHeight / centerHeight;
232 var $ratioWidth = $maxWidth / centerWidth;
233 if ($ratioHeight < $ratioWidth) {
234 centerWidth = Math.round(centerWidth * ($maxHeight / centerHeight));
235 centerHeight = $maxHeight;
236 }
237 else {
238 centerHeight = Math.round(centerHeight * ($maxWidth / centerWidth));
239 centerWidth = $maxWidth;
240 }
241
242 // update dimensions for sizer and navigation links
243 $(sizer).width(centerWidth - 20);
244 $([sizer, prevLink, nextLink]).height(centerHeight - 20);
245 }
246
247 // WoltLab modifications END
248
249 var top = Math.max(0, middle - (centerHeight / 2));
250 if (center.offsetHeight != centerHeight) {
251 $(center).animate({height: centerHeight, top: top}, options.resizeDuration, options.resizeEasing);
252 }
253 if (center.offsetWidth != centerWidth) {
254 $(center).animate({width: centerWidth, marginLeft: -centerWidth/2}, options.resizeDuration, options.resizeEasing);
255 }
256 $(center).queue(function() {
257 $(bottomContainer).css({width: centerWidth, top: top + centerHeight, marginLeft: -centerWidth/2, visibility: "hidden", display: ""});
341b056c
AE
258
259 // WoltLab modifications BEGIN
260
261 // remove spinner
262 $(center).children('.icon-spinner').remove();
263
264 // WoltLab modifications END
265
4c51a0e9
AE
266 $(image).css({display: "none", visibility: "", opacity: ""}).fadeIn(options.imageFadeDuration, animateCaption);
267 });
268 }
269
270 function animateCaption() {
271 if (prevImage >= 0) $(prevLink).show();
272 if (nextImage >= 0) $(nextLink).show();
273 $(bottom).css("marginTop", -bottom.offsetHeight).animate({marginTop: 0}, options.captionAnimationDuration);
274 bottomContainer.style.visibility = "";
275 }
276
277 function stop() {
278 preload.onload = null;
279 preload.src = preloadPrev.src = preloadNext.src = activeURL;
280 $([center, image, bottom]).stop(true);
281 $([prevLink, nextLink, image, bottomContainer]).hide();
282 }
283
284 function close() {
285 if (activeImage >= 0) {
286 stop();
287 activeImage = prevImage = nextImage = -1;
288 $(center).hide();
289 $(overlay).stop().fadeOut(options.overlayFadeDuration, setup);
9e16745a 290
c6771d73
TD
291 // WoltLab modifications BEGIN
292
b2918c9d 293 WCF.System.DisableScrolling.enable();
c6771d73
TD
294
295 // WoltLab modifications END
4c51a0e9
AE
296 }
297
298 return false;
299 }
300
301})(jQuery);