Mercurial > repos > brasset_jensen > srnapipe
comparison test-data/res_files/js/jquery.galleriffic.js @ 61:9185ca0a7b43 draft
Updated package according to recommendations.
author | pierre.pouchin |
---|---|
date | Wed, 16 Jan 2019 08:18:13 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
60:9645d995fb3c | 61:9185ca0a7b43 |
---|---|
1 /** | |
2 * jQuery Galleriffic plugin | |
3 * | |
4 * Copyright (c) 2008 Trent Foley (http://trentacular.com) | |
5 * Licensed under the MIT License: | |
6 * http://www.opensource.org/licenses/mit-license.php | |
7 * | |
8 * Much thanks to primary contributer Ponticlaro (http://www.ponticlaro.com) | |
9 */ | |
10 ;(function($) { | |
11 // Globally keep track of all images by their unique hash. Each item is an image data object. | |
12 var allImages = {}; | |
13 var imageCounter = 0; | |
14 | |
15 // Galleriffic static class | |
16 $.galleriffic = { | |
17 version: '2.0.1', | |
18 | |
19 // Strips invalid characters and any leading # characters | |
20 normalizeHash: function(hash) { | |
21 return hash.replace(/^.*#/, '').replace(/\?.*$/, ''); | |
22 }, | |
23 | |
24 getImage: function(hash) { | |
25 if (!hash) | |
26 return undefined; | |
27 | |
28 hash = $.galleriffic.normalizeHash(hash); | |
29 return allImages[hash]; | |
30 }, | |
31 | |
32 // Global function that looks up an image by its hash and displays the image. | |
33 // Returns false when an image is not found for the specified hash. | |
34 // @param {String} hash This is the unique hash value assigned to an image. | |
35 gotoImage: function(hash) { | |
36 var imageData = $.galleriffic.getImage(hash); | |
37 if (!imageData) | |
38 return false; | |
39 | |
40 var gallery = imageData.gallery; | |
41 gallery.gotoImage(imageData); | |
42 | |
43 return true; | |
44 }, | |
45 | |
46 // Removes an image from its respective gallery by its hash. | |
47 // Returns false when an image is not found for the specified hash or the | |
48 // specified owner gallery does match the located images gallery. | |
49 // @param {String} hash This is the unique hash value assigned to an image. | |
50 // @param {Object} ownerGallery (Optional) When supplied, the located images | |
51 // gallery is verified to be the same as the specified owning gallery before | |
52 // performing the remove operation. | |
53 removeImageByHash: function(hash, ownerGallery) { | |
54 var imageData = $.galleriffic.getImage(hash); | |
55 if (!imageData) | |
56 return false; | |
57 | |
58 var gallery = imageData.gallery; | |
59 if (ownerGallery && ownerGallery != gallery) | |
60 return false; | |
61 | |
62 return gallery.removeImageByIndex(imageData.index); | |
63 } | |
64 }; | |
65 | |
66 var defaults = { | |
67 delay: 3000, | |
68 numThumbs: 20, | |
69 preloadAhead: 40, // Set to -1 to preload all images | |
70 enableTopPager: false, | |
71 enableBottomPager: true, | |
72 maxPagesToShow: 7, | |
73 imageContainerSel: '', | |
74 captionContainerSel: '', | |
75 controlsContainerSel: '', | |
76 loadingContainerSel: '', | |
77 renderSSControls: true, | |
78 renderNavControls: true, | |
79 playLinkText: 'Play', | |
80 pauseLinkText: 'Pause', | |
81 prevLinkText: 'Previous', | |
82 nextLinkText: 'Next', | |
83 nextPageLinkText: 'Next ›', | |
84 prevPageLinkText: '‹ Prev', | |
85 enableHistory: false, | |
86 enableKeyboardNavigation: true, | |
87 autoStart: false, | |
88 syncTransitions: false, | |
89 defaultTransitionDuration: 1000, | |
90 onSlideChange: undefined, // accepts a delegate like such: function(prevIndex, nextIndex) { ... } | |
91 onTransitionOut: undefined, // accepts a delegate like such: function(slide, caption, isSync, callback) { ... } | |
92 onTransitionIn: undefined, // accepts a delegate like such: function(slide, caption, isSync) { ... } | |
93 onPageTransitionOut: undefined, // accepts a delegate like such: function(callback) { ... } | |
94 onPageTransitionIn: undefined, // accepts a delegate like such: function() { ... } | |
95 onImageAdded: undefined, // accepts a delegate like such: function(imageData, $li) { ... } | |
96 onImageRemoved: undefined // accepts a delegate like such: function(imageData, $li) { ... } | |
97 }; | |
98 | |
99 // Primary Galleriffic initialization function that should be called on the thumbnail container. | |
100 $.fn.galleriffic = function(settings) { | |
101 // Extend Gallery Object | |
102 $.extend(this, { | |
103 // Returns the version of the script | |
104 version: $.galleriffic.version, | |
105 | |
106 // Current state of the slideshow | |
107 isSlideshowRunning: false, | |
108 slideshowTimeout: undefined, | |
109 | |
110 // This function is attached to the click event of generated hyperlinks within the gallery | |
111 clickHandler: function(e, link) { | |
112 this.pause(); | |
113 | |
114 if (!this.enableHistory) { | |
115 // The href attribute holds the unique hash for an image | |
116 var hash = $.galleriffic.normalizeHash($(link).attr('href')); | |
117 $.galleriffic.gotoImage(hash); | |
118 e.preventDefault(); | |
119 } | |
120 }, | |
121 | |
122 // Appends an image to the end of the set of images. Argument listItem can be either a jQuery DOM element or arbitrary html. | |
123 // @param listItem Either a jQuery object or a string of html of the list item that is to be added to the gallery. | |
124 appendImage: function(listItem) { | |
125 this.addImage(listItem, false, false); | |
126 return this; | |
127 }, | |
128 | |
129 // Inserts an image into the set of images. Argument listItem can be either a jQuery DOM element or arbitrary html. | |
130 // @param listItem Either a jQuery object or a string of html of the list item that is to be added to the gallery. | |
131 // @param {Integer} position The index within the gallery where the item shouold be added. | |
132 insertImage: function(listItem, position) { | |
133 this.addImage(listItem, false, true, position); | |
134 return this; | |
135 }, | |
136 | |
137 // Adds an image to the gallery and optionally inserts/appends it to the DOM (thumbExists) | |
138 // @param listItem Either a jQuery object or a string of html of the list item that is to be added to the gallery. | |
139 // @param {Boolean} thumbExists Specifies whether the thumbnail already exists in the DOM or if it needs to be added. | |
140 // @param {Boolean} insert Specifies whether the the image is appended to the end or inserted into the gallery. | |
141 // @param {Integer} position The index within the gallery where the item shouold be added. | |
142 addImage: function(listItem, thumbExists, insert, position) { | |
143 var $li = ( typeof listItem === "string" ) ? $(listItem) : listItem; | |
144 var $aThumb = $li.find('a.thumb'); | |
145 var slideUrl = $aThumb.attr('href'); | |
146 var title = $aThumb.attr('title'); | |
147 var $caption = $li.find('.caption').remove(); | |
148 var hash = $aThumb.attr('name'); | |
149 | |
150 // Increment the image counter | |
151 imageCounter++; | |
152 | |
153 // Autogenerate a hash value if none is present or if it is a duplicate | |
154 if (!hash || allImages[''+hash]) { | |
155 hash = imageCounter; | |
156 } | |
157 | |
158 // Set position to end when not specified | |
159 if (!insert) | |
160 position = this.data.length; | |
161 | |
162 var imageData = { | |
163 title:title, | |
164 slideUrl:slideUrl, | |
165 caption:$caption, | |
166 hash:hash, | |
167 gallery:this, | |
168 index:position | |
169 }; | |
170 | |
171 // Add the imageData to this gallery's array of images | |
172 if (insert) { | |
173 this.data.splice(position, 0, imageData); | |
174 | |
175 // Reset index value on all imageData objects | |
176 this.updateIndices(position); | |
177 } | |
178 else { | |
179 this.data.push(imageData); | |
180 } | |
181 | |
182 var gallery = this; | |
183 | |
184 // Add the element to the DOM | |
185 if (!thumbExists) { | |
186 // Update thumbs passing in addition post transition out handler | |
187 this.updateThumbs(function() { | |
188 var $thumbsUl = gallery.find('ul.thumbs'); | |
189 if (insert) | |
190 $thumbsUl.children(':eq('+position+')').before($li); | |
191 else | |
192 $thumbsUl.append($li); | |
193 | |
194 if (gallery.onImageAdded) | |
195 gallery.onImageAdded(imageData, $li); | |
196 }); | |
197 } | |
198 | |
199 // Register the image globally | |
200 allImages[''+hash] = imageData; | |
201 | |
202 // Setup attributes and click handler | |
203 $aThumb.attr('rel', 'history') | |
204 .attr('href', '#'+hash) | |
205 .removeAttr('name') | |
206 .click(function(e) { | |
207 gallery.clickHandler(e, this); | |
208 }); | |
209 | |
210 return this; | |
211 }, | |
212 | |
213 // Removes an image from the gallery based on its index. | |
214 // Returns false when the index is out of range. | |
215 removeImageByIndex: function(index) { | |
216 if (index < 0 || index >= this.data.length) | |
217 return false; | |
218 | |
219 var imageData = this.data[index]; | |
220 if (!imageData) | |
221 return false; | |
222 | |
223 this.removeImage(imageData); | |
224 | |
225 return true; | |
226 }, | |
227 | |
228 // Convenience method that simply calls the global removeImageByHash method. | |
229 removeImageByHash: function(hash) { | |
230 return $.galleriffic.removeImageByHash(hash, this); | |
231 }, | |
232 | |
233 // Removes an image from the gallery. | |
234 removeImage: function(imageData) { | |
235 var index = imageData.index; | |
236 | |
237 // Remove the image from the gallery data array | |
238 this.data.splice(index, 1); | |
239 | |
240 // Remove the global registration | |
241 delete allImages[''+imageData.hash]; | |
242 | |
243 // Remove the image's list item from the DOM | |
244 this.updateThumbs(function() { | |
245 var $li = gallery.find('ul.thumbs') | |
246 .children(':eq('+index+')') | |
247 .remove(); | |
248 | |
249 if (gallery.onImageRemoved) | |
250 gallery.onImageRemoved(imageData, $li); | |
251 }); | |
252 | |
253 // Update each image objects index value | |
254 this.updateIndices(index); | |
255 | |
256 return this; | |
257 }, | |
258 | |
259 // Updates the index values of the each of the images in the gallery after the specified index | |
260 updateIndices: function(startIndex) { | |
261 for (i = startIndex; i < this.data.length; i++) { | |
262 this.data[i].index = i; | |
263 } | |
264 | |
265 return this; | |
266 }, | |
267 | |
268 // Scraped the thumbnail container for thumbs and adds each to the gallery | |
269 initializeThumbs: function() { | |
270 this.data = []; | |
271 var gallery = this; | |
272 | |
273 this.find('ul.thumbs > li').each(function(i) { | |
274 gallery.addImage($(this), true, false); | |
275 }); | |
276 | |
277 return this; | |
278 }, | |
279 | |
280 isPreloadComplete: false, | |
281 | |
282 // Initalizes the image preloader | |
283 preloadInit: function() { | |
284 if (this.preloadAhead == 0) return this; | |
285 | |
286 this.preloadStartIndex = this.currentImage.index; | |
287 var nextIndex = this.getNextIndex(this.preloadStartIndex); | |
288 return this.preloadRecursive(this.preloadStartIndex, nextIndex); | |
289 }, | |
290 | |
291 // Changes the location in the gallery the preloader should work | |
292 // @param {Integer} index The index of the image where the preloader should restart at. | |
293 preloadRelocate: function(index) { | |
294 // By changing this startIndex, the current preload script will restart | |
295 this.preloadStartIndex = index; | |
296 return this; | |
297 }, | |
298 | |
299 // Recursive function that performs the image preloading | |
300 // @param {Integer} startIndex The index of the first image the current preloader started on. | |
301 // @param {Integer} currentIndex The index of the current image to preload. | |
302 preloadRecursive: function(startIndex, currentIndex) { | |
303 // Check if startIndex has been relocated | |
304 if (startIndex != this.preloadStartIndex) { | |
305 var nextIndex = this.getNextIndex(this.preloadStartIndex); | |
306 return this.preloadRecursive(this.preloadStartIndex, nextIndex); | |
307 } | |
308 | |
309 var gallery = this; | |
310 | |
311 // Now check for preloadAhead count | |
312 var preloadCount = currentIndex - startIndex; | |
313 if (preloadCount < 0) | |
314 preloadCount = this.data.length-1-startIndex+currentIndex; | |
315 if (this.preloadAhead >= 0 && preloadCount > this.preloadAhead) { | |
316 // Do this in order to keep checking for relocated start index | |
317 setTimeout(function() { gallery.preloadRecursive(startIndex, currentIndex); }, 500); | |
318 return this; | |
319 } | |
320 | |
321 var imageData = this.data[currentIndex]; | |
322 if (!imageData) | |
323 return this; | |
324 | |
325 // If already loaded, continue | |
326 if (imageData.image) | |
327 return this.preloadNext(startIndex, currentIndex); | |
328 | |
329 // Preload the image | |
330 var image = new Image(); | |
331 | |
332 image.onload = function() { | |
333 imageData.image = this; | |
334 gallery.preloadNext(startIndex, currentIndex); | |
335 }; | |
336 | |
337 image.alt = imageData.title; | |
338 image.src = imageData.slideUrl; | |
339 | |
340 return this; | |
341 }, | |
342 | |
343 // Called by preloadRecursive in order to preload the next image after the previous has loaded. | |
344 // @param {Integer} startIndex The index of the first image the current preloader started on. | |
345 // @param {Integer} currentIndex The index of the current image to preload. | |
346 preloadNext: function(startIndex, currentIndex) { | |
347 var nextIndex = this.getNextIndex(currentIndex); | |
348 if (nextIndex == startIndex) { | |
349 this.isPreloadComplete = true; | |
350 } else { | |
351 // Use setTimeout to free up thread | |
352 var gallery = this; | |
353 setTimeout(function() { gallery.preloadRecursive(startIndex, nextIndex); }, 100); | |
354 } | |
355 | |
356 return this; | |
357 }, | |
358 | |
359 // Safe way to get the next image index relative to the current image. | |
360 // If the current image is the last, returns 0 | |
361 getNextIndex: function(index) { | |
362 var nextIndex = index+1; | |
363 if (nextIndex >= this.data.length) | |
364 nextIndex = 0; | |
365 return nextIndex; | |
366 }, | |
367 | |
368 // Safe way to get the previous image index relative to the current image. | |
369 // If the current image is the first, return the index of the last image in the gallery. | |
370 getPrevIndex: function(index) { | |
371 var prevIndex = index-1; | |
372 if (prevIndex < 0) | |
373 prevIndex = this.data.length-1; | |
374 return prevIndex; | |
375 }, | |
376 | |
377 // Pauses the slideshow | |
378 pause: function() { | |
379 this.isSlideshowRunning = false; | |
380 if (this.slideshowTimeout) { | |
381 clearTimeout(this.slideshowTimeout); | |
382 this.slideshowTimeout = undefined; | |
383 } | |
384 | |
385 if (this.$controlsContainer) { | |
386 this.$controlsContainer | |
387 .find('div.ss-controls a').removeClass().addClass('play') | |
388 .attr('title', this.playLinkText) | |
389 .attr('href', '#play') | |
390 .html(this.playLinkText); | |
391 } | |
392 | |
393 return this; | |
394 }, | |
395 | |
396 // Plays the slideshow | |
397 play: function() { | |
398 this.isSlideshowRunning = true; | |
399 | |
400 if (this.$controlsContainer) { | |
401 this.$controlsContainer | |
402 .find('div.ss-controls a').removeClass().addClass('pause') | |
403 .attr('title', this.pauseLinkText) | |
404 .attr('href', '#pause') | |
405 .html(this.pauseLinkText); | |
406 } | |
407 | |
408 if (!this.slideshowTimeout) { | |
409 var gallery = this; | |
410 this.slideshowTimeout = setTimeout(function() { gallery.ssAdvance(); }, this.delay); | |
411 } | |
412 | |
413 return this; | |
414 }, | |
415 | |
416 // Toggles the state of the slideshow (playing/paused) | |
417 toggleSlideshow: function() { | |
418 if (this.isSlideshowRunning) | |
419 this.pause(); | |
420 else | |
421 this.play(); | |
422 | |
423 return this; | |
424 }, | |
425 | |
426 // Advances the slideshow to the next image and delegates navigation to the | |
427 // history plugin when history is enabled | |
428 // enableHistory is true | |
429 ssAdvance: function() { | |
430 if (this.isSlideshowRunning) | |
431 this.next(true); | |
432 | |
433 return this; | |
434 }, | |
435 | |
436 // Advances the gallery to the next image. | |
437 // @param {Boolean} dontPause Specifies whether to pause the slideshow. | |
438 // @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled. | |
439 next: function(dontPause, bypassHistory) { | |
440 this.gotoIndex(this.getNextIndex(this.currentImage.index), dontPause, bypassHistory); | |
441 return this; | |
442 }, | |
443 | |
444 // Navigates to the previous image in the gallery. | |
445 // @param {Boolean} dontPause Specifies whether to pause the slideshow. | |
446 // @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled. | |
447 previous: function(dontPause, bypassHistory) { | |
448 this.gotoIndex(this.getPrevIndex(this.currentImage.index), dontPause, bypassHistory); | |
449 return this; | |
450 }, | |
451 | |
452 // Navigates to the next page in the gallery. | |
453 // @param {Boolean} dontPause Specifies whether to pause the slideshow. | |
454 // @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled. | |
455 nextPage: function(dontPause, bypassHistory) { | |
456 var page = this.getCurrentPage(); | |
457 var lastPage = this.getNumPages() - 1; | |
458 if (page < lastPage) { | |
459 var startIndex = page * this.numThumbs; | |
460 var nextPage = startIndex + this.numThumbs; | |
461 this.gotoIndex(nextPage, dontPause, bypassHistory); | |
462 } | |
463 | |
464 return this; | |
465 }, | |
466 | |
467 // Navigates to the previous page in the gallery. | |
468 // @param {Boolean} dontPause Specifies whether to pause the slideshow. | |
469 // @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled. | |
470 previousPage: function(dontPause, bypassHistory) { | |
471 var page = this.getCurrentPage(); | |
472 if (page > 0) { | |
473 var startIndex = page * this.numThumbs; | |
474 var prevPage = startIndex - this.numThumbs; | |
475 this.gotoIndex(prevPage, dontPause, bypassHistory); | |
476 } | |
477 | |
478 return this; | |
479 }, | |
480 | |
481 // Navigates to the image at the specified index in the gallery | |
482 // @param {Integer} index The index of the image in the gallery to display. | |
483 // @param {Boolean} dontPause Specifies whether to pause the slideshow. | |
484 // @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled. | |
485 gotoIndex: function(index, dontPause, bypassHistory) { | |
486 if (!dontPause) | |
487 this.pause(); | |
488 | |
489 if (index < 0) index = 0; | |
490 else if (index >= this.data.length) index = this.data.length-1; | |
491 | |
492 var imageData = this.data[index]; | |
493 | |
494 if (!bypassHistory && this.enableHistory) | |
495 $.historyLoad(String(imageData.hash)); // At the moment, historyLoad only accepts string arguments | |
496 else | |
497 this.gotoImage(imageData); | |
498 | |
499 return this; | |
500 }, | |
501 | |
502 // This function is garaunteed to be called anytime a gallery slide changes. | |
503 // @param {Object} imageData An object holding the image metadata of the image to navigate to. | |
504 gotoImage: function(imageData) { | |
505 var index = imageData.index; | |
506 | |
507 if (this.onSlideChange) | |
508 this.onSlideChange(this.currentImage.index, index); | |
509 | |
510 this.currentImage = imageData; | |
511 this.preloadRelocate(index); | |
512 | |
513 this.refresh(); | |
514 | |
515 return this; | |
516 }, | |
517 | |
518 // Returns the default transition duration value. The value is halved when not | |
519 // performing a synchronized transition. | |
520 // @param {Boolean} isSync Specifies whether the transitions are synchronized. | |
521 getDefaultTransitionDuration: function(isSync) { | |
522 if (isSync) | |
523 return this.defaultTransitionDuration; | |
524 return this.defaultTransitionDuration / 2; | |
525 }, | |
526 | |
527 // Rebuilds the slideshow image and controls and performs transitions | |
528 refresh: function() { | |
529 var imageData = this.currentImage; | |
530 if (!imageData) | |
531 return this; | |
532 | |
533 var index = imageData.index; | |
534 | |
535 // Update Controls | |
536 if (this.$controlsContainer) { | |
537 this.$controlsContainer | |
538 .find('div.nav-controls a.prev').attr('href', '#'+this.data[this.getPrevIndex(index)].hash).end() | |
539 .find('div.nav-controls a.next').attr('href', '#'+this.data[this.getNextIndex(index)].hash); | |
540 } | |
541 | |
542 var previousSlide = this.$imageContainer.find('span.current').addClass('previous').removeClass('current'); | |
543 var previousCaption = 0; | |
544 | |
545 if (this.$captionContainer) { | |
546 previousCaption = this.$captionContainer.find('span.current').addClass('previous').removeClass('current'); | |
547 } | |
548 | |
549 // Perform transitions simultaneously if syncTransitions is true and the next image is already preloaded | |
550 var isSync = this.syncTransitions && imageData.image; | |
551 | |
552 // Flag we are transitioning | |
553 var isTransitioning = true; | |
554 var gallery = this; | |
555 | |
556 var transitionOutCallback = function() { | |
557 // Flag that the transition has completed | |
558 isTransitioning = false; | |
559 | |
560 // Remove the old slide | |
561 previousSlide.remove(); | |
562 | |
563 // Remove old caption | |
564 if (previousCaption) | |
565 previousCaption.remove(); | |
566 | |
567 if (!isSync) { | |
568 if (imageData.image && imageData.hash == gallery.data[gallery.currentImage.index].hash) { | |
569 gallery.buildImage(imageData, isSync); | |
570 } else { | |
571 // Show loading container | |
572 if (gallery.$loadingContainer) { | |
573 gallery.$loadingContainer.show(); | |
574 } | |
575 } | |
576 } | |
577 }; | |
578 | |
579 if (previousSlide.length == 0) { | |
580 // For the first slide, the previous slide will be empty, so we will call the callback immediately | |
581 transitionOutCallback(); | |
582 } else { | |
583 if (this.onTransitionOut) { | |
584 this.onTransitionOut(previousSlide, previousCaption, isSync, transitionOutCallback); | |
585 } else { | |
586 previousSlide.fadeTo(this.getDefaultTransitionDuration(isSync), 0.0, transitionOutCallback); | |
587 if (previousCaption) | |
588 previousCaption.fadeTo(this.getDefaultTransitionDuration(isSync), 0.0); | |
589 } | |
590 } | |
591 | |
592 // Go ahead and begin transitioning in of next image | |
593 if (isSync) | |
594 this.buildImage(imageData, isSync); | |
595 | |
596 if (!imageData.image) { | |
597 var image = new Image(); | |
598 | |
599 // Wire up mainImage onload event | |
600 image.onload = function() { | |
601 imageData.image = this; | |
602 | |
603 // Only build image if the out transition has completed and we are still on the same image hash | |
604 if (!isTransitioning && imageData.hash == gallery.data[gallery.currentImage.index].hash) { | |
605 gallery.buildImage(imageData, isSync); | |
606 } | |
607 }; | |
608 | |
609 // set alt and src | |
610 image.alt = imageData.title; | |
611 image.src = imageData.slideUrl; | |
612 } | |
613 | |
614 // This causes the preloader (if still running) to relocate out from the currentIndex | |
615 this.relocatePreload = true; | |
616 | |
617 return this.syncThumbs(); | |
618 }, | |
619 | |
620 // Called by the refresh method after the previous image has been transitioned out or at the same time | |
621 // as the out transition when performing a synchronous transition. | |
622 // @param {Object} imageData An object holding the image metadata of the image to build. | |
623 // @param {Boolean} isSync Specifies whether the transitions are synchronized. | |
624 buildImage: function(imageData, isSync) { | |
625 var gallery = this; | |
626 var nextIndex = this.getNextIndex(imageData.index); | |
627 | |
628 // Construct new hidden span for the image | |
629 var newSlide = this.$imageContainer | |
630 .append('<span class="image-wrapper current"><a class="advance-link" rel="history" href="#'+this.data[nextIndex].hash+'" title="'+imageData.title+'"> </a></span>') | |
631 .find('span.current').css('opacity', '0'); | |
632 | |
633 newSlide.find('a') | |
634 .append(imageData.image) | |
635 .click(function(e) { | |
636 gallery.clickHandler(e, this); | |
637 }); | |
638 | |
639 var newCaption = 0; | |
640 if (this.$captionContainer) { | |
641 // Construct new hidden caption for the image | |
642 newCaption = this.$captionContainer | |
643 .append('<span class="image-caption current"></span>') | |
644 .find('span.current').css('opacity', '0') | |
645 .append(imageData.caption); | |
646 } | |
647 | |
648 // Hide the loading conatiner | |
649 if (this.$loadingContainer) { | |
650 this.$loadingContainer.hide(); | |
651 } | |
652 | |
653 // Transition in the new image | |
654 if (this.onTransitionIn) { | |
655 this.onTransitionIn(newSlide, newCaption, isSync); | |
656 } else { | |
657 newSlide.fadeTo(this.getDefaultTransitionDuration(isSync), 1.0); | |
658 if (newCaption) | |
659 newCaption.fadeTo(this.getDefaultTransitionDuration(isSync), 1.0); | |
660 } | |
661 | |
662 if (this.isSlideshowRunning) { | |
663 if (this.slideshowTimeout) | |
664 clearTimeout(this.slideshowTimeout); | |
665 | |
666 this.slideshowTimeout = setTimeout(function() { gallery.ssAdvance(); }, this.delay); | |
667 } | |
668 | |
669 return this; | |
670 }, | |
671 | |
672 // Returns the current page index that should be shown for the currentImage | |
673 getCurrentPage: function() { | |
674 return Math.floor(this.currentImage.index / this.numThumbs); | |
675 }, | |
676 | |
677 // Applies the selected class to the current image's corresponding thumbnail. | |
678 // Also checks if the current page has changed and updates the displayed page of thumbnails if necessary. | |
679 syncThumbs: function() { | |
680 var page = this.getCurrentPage(); | |
681 if (page != this.displayedPage) | |
682 this.updateThumbs(); | |
683 | |
684 // Remove existing selected class and add selected class to new thumb | |
685 var $thumbs = this.find('ul.thumbs').children(); | |
686 $thumbs.filter('.selected').removeClass('selected'); | |
687 $thumbs.eq(this.currentImage.index).addClass('selected'); | |
688 | |
689 return this; | |
690 }, | |
691 | |
692 // Performs transitions on the thumbnails container and updates the set of | |
693 // thumbnails that are to be displayed and the navigation controls. | |
694 // @param {Delegate} postTransitionOutHandler An optional delegate that is called after | |
695 // the thumbnails container has transitioned out and before the thumbnails are rebuilt. | |
696 updateThumbs: function(postTransitionOutHandler) { | |
697 var gallery = this; | |
698 var transitionOutCallback = function() { | |
699 // Call the Post-transition Out Handler | |
700 if (postTransitionOutHandler) | |
701 postTransitionOutHandler(); | |
702 | |
703 gallery.rebuildThumbs(); | |
704 | |
705 // Transition In the thumbsContainer | |
706 if (gallery.onPageTransitionIn) | |
707 gallery.onPageTransitionIn(); | |
708 else | |
709 gallery.show(); | |
710 }; | |
711 | |
712 // Transition Out the thumbsContainer | |
713 if (this.onPageTransitionOut) { | |
714 this.onPageTransitionOut(transitionOutCallback); | |
715 } else { | |
716 this.hide(); | |
717 transitionOutCallback(); | |
718 } | |
719 | |
720 return this; | |
721 }, | |
722 | |
723 // Updates the set of thumbnails that are to be displayed and the navigation controls. | |
724 rebuildThumbs: function() { | |
725 var needsPagination = this.data.length > this.numThumbs; | |
726 | |
727 // Rebuild top pager | |
728 if (this.enableTopPager) { | |
729 var $topPager = this.find('div.top'); | |
730 if ($topPager.length == 0) | |
731 $topPager = this.prepend('<div class="top pagination"></div>').find('div.top'); | |
732 else | |
733 $topPager.empty(); | |
734 | |
735 if (needsPagination) | |
736 this.buildPager($topPager); | |
737 } | |
738 | |
739 // Rebuild bottom pager | |
740 if (this.enableBottomPager) { | |
741 var $bottomPager = this.find('div.bottom'); | |
742 if ($bottomPager.length == 0) | |
743 $bottomPager = this.append('<div class="bottom pagination"></div>').find('div.bottom'); | |
744 else | |
745 $bottomPager.empty(); | |
746 | |
747 if (needsPagination) | |
748 this.buildPager($bottomPager); | |
749 } | |
750 | |
751 var page = this.getCurrentPage(); | |
752 var startIndex = page*this.numThumbs; | |
753 var stopIndex = startIndex+this.numThumbs-1; | |
754 if (stopIndex >= this.data.length) | |
755 stopIndex = this.data.length-1; | |
756 | |
757 // Show/Hide thumbs | |
758 var $thumbsUl = this.find('ul.thumbs'); | |
759 $thumbsUl.find('li').each(function(i) { | |
760 var $li = $(this); | |
761 if (i >= startIndex && i <= stopIndex) { | |
762 $li.show(); | |
763 } else { | |
764 $li.hide(); | |
765 } | |
766 }); | |
767 | |
768 this.displayedPage = page; | |
769 | |
770 // Remove the noscript class from the thumbs container ul | |
771 $thumbsUl.removeClass('noscript'); | |
772 | |
773 return this; | |
774 }, | |
775 | |
776 // Returns the total number of pages required to display all the thumbnails. | |
777 getNumPages: function() { | |
778 return Math.ceil(this.data.length/this.numThumbs); | |
779 }, | |
780 | |
781 // Rebuilds the pager control in the specified matched element. | |
782 // @param {jQuery} pager A jQuery element set matching the particular pager to be rebuilt. | |
783 buildPager: function(pager) { | |
784 var gallery = this; | |
785 var numPages = this.getNumPages(); | |
786 var page = this.getCurrentPage(); | |
787 var startIndex = page * this.numThumbs; | |
788 var pagesRemaining = this.maxPagesToShow - 1; | |
789 | |
790 var pageNum = page - Math.floor((this.maxPagesToShow - 1) / 2) + 1; | |
791 if (pageNum > 0) { | |
792 var remainingPageCount = numPages - pageNum; | |
793 if (remainingPageCount < pagesRemaining) { | |
794 pageNum = pageNum - (pagesRemaining - remainingPageCount); | |
795 } | |
796 } | |
797 | |
798 if (pageNum < 0) { | |
799 pageNum = 0; | |
800 } | |
801 | |
802 // Prev Page Link | |
803 if (page > 0) { | |
804 var prevPage = startIndex - this.numThumbs; | |
805 pager.append('<a rel="history" href="#'+this.data[prevPage].hash+'" title="'+this.prevPageLinkText+'">'+this.prevPageLinkText+'</a>'); | |
806 } | |
807 | |
808 // Create First Page link if needed | |
809 if (pageNum > 0) { | |
810 this.buildPageLink(pager, 0, numPages); | |
811 if (pageNum > 1) | |
812 pager.append('<span class="ellipsis">…</span>'); | |
813 | |
814 pagesRemaining--; | |
815 } | |
816 | |
817 // Page Index Links | |
818 while (pagesRemaining > 0) { | |
819 this.buildPageLink(pager, pageNum, numPages); | |
820 pagesRemaining--; | |
821 pageNum++; | |
822 } | |
823 | |
824 // Create Last Page link if needed | |
825 if (pageNum < numPages) { | |
826 var lastPageNum = numPages - 1; | |
827 if (pageNum < lastPageNum) | |
828 pager.append('<span class="ellipsis">…</span>'); | |
829 | |
830 this.buildPageLink(pager, lastPageNum, numPages); | |
831 } | |
832 | |
833 // Next Page Link | |
834 var nextPage = startIndex + this.numThumbs; | |
835 if (nextPage < this.data.length) { | |
836 pager.append('<a rel="history" href="#'+this.data[nextPage].hash+'" title="'+this.nextPageLinkText+'">'+this.nextPageLinkText+'</a>'); | |
837 } | |
838 | |
839 pager.find('a').click(function(e) { | |
840 gallery.clickHandler(e, this); | |
841 }); | |
842 | |
843 return this; | |
844 }, | |
845 | |
846 // Builds a single page link within a pager. This function is called by buildPager | |
847 // @param {jQuery} pager A jQuery element set matching the particular pager to be rebuilt. | |
848 // @param {Integer} pageNum The page number of the page link to build. | |
849 // @param {Integer} numPages The total number of pages required to display all thumbnails. | |
850 buildPageLink: function(pager, pageNum, numPages) { | |
851 var pageLabel = pageNum + 1; | |
852 var currentPage = this.getCurrentPage(); | |
853 if (pageNum == currentPage) | |
854 pager.append('<span class="current">'+pageLabel+'</span>'); | |
855 else if (pageNum < numPages) { | |
856 var imageIndex = pageNum*this.numThumbs; | |
857 pager.append('<a rel="history" href="#'+this.data[imageIndex].hash+'" title="'+pageLabel+'">'+pageLabel+'</a>'); | |
858 } | |
859 | |
860 return this; | |
861 } | |
862 }); | |
863 | |
864 // Now initialize the gallery | |
865 $.extend(this, defaults, settings); | |
866 | |
867 // Verify the history plugin is available | |
868 if (this.enableHistory && !$.historyInit) | |
869 this.enableHistory = false; | |
870 | |
871 // Select containers | |
872 if (this.imageContainerSel) this.$imageContainer = $(this.imageContainerSel); | |
873 if (this.captionContainerSel) this.$captionContainer = $(this.captionContainerSel); | |
874 if (this.loadingContainerSel) this.$loadingContainer = $(this.loadingContainerSel); | |
875 | |
876 // Initialize the thumbails | |
877 this.initializeThumbs(); | |
878 | |
879 if (this.maxPagesToShow < 3) | |
880 this.maxPagesToShow = 3; | |
881 | |
882 this.displayedPage = -1; | |
883 this.currentImage = this.data[0]; | |
884 var gallery = this; | |
885 | |
886 // Hide the loadingContainer | |
887 if (this.$loadingContainer) | |
888 this.$loadingContainer.hide(); | |
889 | |
890 // Setup controls | |
891 if (this.controlsContainerSel) { | |
892 this.$controlsContainer = $(this.controlsContainerSel).empty(); | |
893 | |
894 if (this.renderSSControls) { | |
895 if (this.autoStart) { | |
896 this.$controlsContainer | |
897 .append('<div class="ss-controls"><a href="#pause" class="pause" title="'+this.pauseLinkText+'">'+this.pauseLinkText+'</a></div>'); | |
898 } else { | |
899 this.$controlsContainer | |
900 .append('<div class="ss-controls"><a href="#play" class="play" title="'+this.playLinkText+'">'+this.playLinkText+'</a></div>'); | |
901 } | |
902 | |
903 this.$controlsContainer.find('div.ss-controls a') | |
904 .click(function(e) { | |
905 gallery.toggleSlideshow(); | |
906 e.preventDefault(); | |
907 return false; | |
908 }); | |
909 } | |
910 | |
911 if (this.renderNavControls) { | |
912 this.$controlsContainer | |
913 .append('<div class="nav-controls"><a class="prev" rel="history" title="'+this.prevLinkText+'">'+this.prevLinkText+'</a><a class="next" rel="history" title="'+this.nextLinkText+'">'+this.nextLinkText+'</a></div>') | |
914 .find('div.nav-controls a') | |
915 .click(function(e) { | |
916 gallery.clickHandler(e, this); | |
917 }); | |
918 } | |
919 } | |
920 | |
921 var initFirstImage = !this.enableHistory || !location.hash; | |
922 if (this.enableHistory && location.hash) { | |
923 var hash = $.galleriffic.normalizeHash(location.hash); | |
924 var imageData = allImages[hash]; | |
925 if (!imageData) | |
926 initFirstImage = true; | |
927 } | |
928 | |
929 // Setup gallery to show the first image | |
930 if (initFirstImage) | |
931 this.gotoIndex(0, false, true); | |
932 | |
933 // Setup Keyboard Navigation | |
934 if (this.enableKeyboardNavigation) { | |
935 $(document).keydown(function(e) { | |
936 var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0; | |
937 switch(key) { | |
938 case 32: // space | |
939 gallery.next(); | |
940 e.preventDefault(); | |
941 break; | |
942 case 33: // Page Up | |
943 gallery.previousPage(); | |
944 e.preventDefault(); | |
945 break; | |
946 case 34: // Page Down | |
947 gallery.nextPage(); | |
948 e.preventDefault(); | |
949 break; | |
950 case 35: // End | |
951 gallery.gotoIndex(gallery.data.length-1); | |
952 e.preventDefault(); | |
953 break; | |
954 case 36: // Home | |
955 gallery.gotoIndex(0); | |
956 e.preventDefault(); | |
957 break; | |
958 case 37: // left arrow | |
959 gallery.previous(); | |
960 e.preventDefault(); | |
961 break; | |
962 case 39: // right arrow | |
963 gallery.next(); | |
964 e.preventDefault(); | |
965 break; | |
966 } | |
967 }); | |
968 } | |
969 | |
970 // Auto start the slideshow | |
971 if (this.autoStart) | |
972 this.play(); | |
973 | |
974 // Kickoff Image Preloader after 1 second | |
975 setTimeout(function() { gallery.preloadInit(); }, 1000); | |
976 | |
977 return this; | |
978 }; | |
979 })(jQuery); |