PageSourceSearch

https://yungash-school.ru/modules/mod_artfeaturecarousel/js/jquery.featureCarousel.js

js yungash-school.ru collected 2026-10-08 00:52:09 UTC 32,069 bytes, 660 lines download raw bytes

1/*!
2 * Feature Carousel, Version 1.0
3 * http://www.bkosolutions.com
4 *
5 * Copyright 2010 Brian Osborne
6 * Licensed under GPL version 3
7 *
8 * http://www.gnu.org/licenses/gpl.txt
9 */
10(function($) {
11
12    $.fn.featureCarousel = function (options) {
13
14        // override the default options with user defined options
15        options = $.extend({}, $.fn.featureCarousel.defaults, options || {});
16
17        return $(this).each(function () {
18
19            /* These are univeral values that are used throughout the plugin. Do not modify them
20             * unless you know what you're doing. Most of them feed off the options
21             * so most customization can be achieved by modifying the options values */
22            var pluginData = {
23                currentCenterNum:       options.startingFeature,
24                containerWidth:         0,
25                containerHeight:        0,
26                largeFeatureWidth:      0,
27                largeFeatureHeight:     0,
28                smallFeatureWidth:      0,
29                smallFeatureHeight:     0,
30                totalFeatureCount:      $(this).children("div").length,
31                currentlyMoving:        false,
32                featuresContainer:      $(this),
33                featuresArray:          [],
34                containerIDTag:         "#"+$(this).attr("id"),
35                timeoutVar:             null,
36                rotationsRemaining:     0,
37                itemsToAnimate:         0,
38                borderWidth:			0
39            };
40
41            	setupFeatureDimensions();
42                setupCarousel();
43                setupFeaturePositions();
44                setupBlips();
45                initiateMove(true,1);
46
47            /**
48             * Function to preload the images in the carousel if desired.
49             * This is not recommended if there are a lot of images in the carousel because
50             * it may take a while. Functionality does not depend on preloading the images
51             */
52            function preload(callback) {
53                // user may not want to preload images
54                if (options.preload == true) {
55                    var $imageElements = pluginData.featuresContainer.find("img");
56                    var loadedImages = 0;
57                    var totalImages = $imageElements.length;
58
59                    $imageElements.each(function () {
60                        // Attempt to load the images
61                        $(this).load(function () {
62                            // Add to number of images loaded and see if they are all done yet
63                            loadedImages++;
64                            if (loadedImages == totalImages) {
65                                // All done, perform callback
66                                callback();
67                            }
68                        });
69                        // The images may already be cached in the browser, in which case they
70                        // would have a 'true' complete value and the load callback would never be
71                        // fired. This will fire it manually.
72                        if (this.complete) {
73                            $(this).trigger('load');
74                        }
75                    });
76                } else {
77                    // if user doesn't want preloader, then just go right to callback
78                    callback();
79                }
80            }
81
82            // Gets the feature container based on the number
83            function getContainer(featureNum) {
84                return pluginData.featuresArray[featureNum-1];
85            }
86
87            // get a feature given it's set position (the position that doesn't change)
88            function getBySetPos(position) {
89                $.each(pluginData.featuresArray, function () {
90                    if ($(this).data().setPosition == position)
91                        return $(this);
92                });
93            }
94
95            // get previous feature number
96            function getPreviousNum(num) {
97                if ((num - 1) == 0) {
98                    return pluginData.totalFeatureCount;
99                } else {
100                    return num - 1;
101                }
102            }
103
104            // get next feature number
105            function getNextNum(num) {
106                if ((num + 1) > pluginData.totalFeatureCount) {
107                    return 1;
108                } else {
109                    return num + 1;
110                }
111            }
112
113            /**
114             * Because there are several options the user can set for the width and height
115             * of the feature images, this function is used to determine which options were set
116             * and to set the appropriate dimensions used for a small and large feature
117             */
118            function setupFeatureDimensions() {
119                // Set the height and width of the entire carousel container
120                pluginData.containerWidth = pluginData.featuresContainer.outerWidth();
121                pluginData.containerHeight = pluginData.featuresContainer.outerHeight();
122
123                // Grab the first image for reference
124                var $firstFeatureImage = $(pluginData.containerIDTag).find("div img:first");
125
126                // Large Feature Width
127                if (options.largeFeatureWidth > 1)
128                    pluginData.largeFeatureWidth = options.largeFeatureWidth;
129                else if (options.largeFeatureWidth > 0 && options.largeFeatureWidth < 1)
130                    pluginData.largeFeatureWidth = $firstFeatureImage.
130width() * options.largeFeatureWidth;
131                else
132                    pluginData.largeFeatureWidth = $firstFeatureImage.outerWidth();
133                // Large Feature Height
134                if (options.largeFeatureHeight > 1)
135                    pluginData.largeFeatureHeight = options.largeFeatureHeight;
136                else if (options.largeFeatureHeight > 0 && options.largeFeatureHeight < 1)
137                    pluginData.largeFeatureHeight = $firstFeatureImage.height() * options.largeFeatureHeight;
138                else
139                    pluginData.largeFeatureHeight = $firstFeatureImage.outerHeight();
140                // Small Feature Width
141                if (options.smallFeatureWidth > 1)
142                    pluginData.smallFeatureWidth = options.smallFeatureWidth;
143                else if (options.smallFeatureWidth > 0 && options.smallFeatureWidth < 1)
144                    pluginData.smallFeatureWidth = $firstFeatureImage.width() * options.smallFeatureWidth;
145                else
146                    pluginData.smallFeatureWidth = $firstFeatureImage.outerWidth() / 2;
147                // Small Feature Height
148                if (options.smallFeatureHeight > 1)
149                    pluginData.smallFeatureHeight = options.smallFeatureHeight;
150                else if (options.smallFeatureHeight > 0 && options.smallFeatureHeight < 1)
151                    pluginData.smallFeatureHeight = $firstFeatureImage.height() * options.smallFeatureHeight;
152                else
153                    pluginData.smallFeatureHeight = $firstFeatureImage.outerHeight() / 2;
154            }
155
156            /**
157             * Function to take care of setting up various aspects of the carousel,
158             * most importantly the default positions for the features
159             */
160            function setupCarousel() {
161                // Set the total feature count to the amount the user wanted to cutoff
162                if (options.displayCutoff > 0 && options.displayCutoff < pluginData.totalFeatureCount) {
163                    pluginData.totalFeatureCount = options.displayCutoff;
164                }
165
166                // fill in the features array
167                pluginData.featuresContainer.children("div").each(function (index) {
168                    if (index < pluginData.totalFeatureCount) {
169                        pluginData.featuresArray[index] = $(this);
170                    }
171                });
172
173                // Determine the total border width around the feature if there is one
174                if (pluginData.featuresContainer.children("div").first().css("borderLeftWidth") != "medium") {
175                    pluginData.borderWidth = parseInt(pluginData.featuresContainer.children("div").first().css("borderLeftWidth"))*2;
176                }
177
178                // Place all the features in a center hidden position to start off
179                pluginData.featuresContainer
180                    // Have to make the container relative positioning
181                    .children("div").each(function () {
182                        // Center all the features in the middle and hide them
183                        $(this).css({
184                            'left': (pluginData.containerWidth / 2) - (pluginData.smallFeatureWidth / 2) - (pluginData.borderWidth / 2),
185                            'width': pluginData.smallFeatureWidth,
186                            'height': pluginData.smallFeatureHeight,
187                            'top': options.smallFeatureOffset + options.topPadding,
188                            'opacity': 0
189                        });
190                    })
191                    // Set all the images to small feature size
192                    .find("img:first").css({
193                        'width': pluginData.smallFeatureWidth
194                    });
195
196                // figure out number of items that will rotate each time
197                if (pluginData.totalFeatureCount < 4) {
198                    pluginData.itemsToAnimate = pluginData.totalFeatureCount;
199                } else {
200                    pluginData.itemsToAnimate = 4;
201                }
202
203                // Hide story info and set the proper positioning
204                pluginData.featuresContainer.find("div > div")
205                    .hide();
206            }
207
208            /**
209             * Here all the position data is set for the features.
210             * This is an important part of the carousel to keep track of where
211             * each feature within the carousel is
212             */
213            function setupFeaturePositions() {
214                // give all features a set number that won't change so they remember their
215                // original order
216                $.each(pluginData.featuresArray, function (i) {
217                    $(this).data('setPosition',i+1);
218                });
219
220                // Go back one - This is done because we call the move function right away, which
221                // shifts everything to the right. So we set the current center back one, so that
222                // it displays in the center when that happens
223                var oneBeforeStarting = getPreviousNum(options.startingFeature);
224                pluginData.currentCenterNum = oneBeforeStarting;
225
226                // Center feature will be position 1
227                var $centerFeature = getContainer(oneBeforeStarting);
228                $centerFeature.data('position',1);
229
230                // Everything before that center feature...
231                var $prevFeatures = $centerFeature.prevAll();
232                $prevFeatures.each(function (i) {
233                    $(this).data('position',(pluginData.totalFeatureCount - i
233));
234                });
235
236                // And everything after that center feature...
237                var $nextFeatures = $centerFeature.nextAll();
238                $nextFeatures.each(function (i) {
239                    if ($(this).data('setPosition') != undefined) {
240                        $(this).data('position',(i + 2));
241                    }
242                });
243
244                // if the counter style is for including number tags in description...
245                if (options.counterStyle == 3) {
246                    $.each(pluginData.featuresArray, function () {
247                        var pos = getPreviousNum($(this).data('position'));
248                        var $numberTag = $("<span></span>");
249                        $numberTag.addClass("numberTag");
250                        $numberTag.html("("+ pos + " of " + pluginData.totalFeatureCount + ") ");
251                        $(this).find('div p').prepend($numberTag);
252                    });
253                }
254            }
255
256            /**
257             * The blips are built using this function. The position and look
258             * of the blips are completely determined by the CSS file
259             */
260            function setupBlips()
261            {
262                // Only setup the blips if the counter style is 1 or 2
263                if (options.counterStyle == 1 || options.counterStyle == 2) {
264                    // construct the blip list
265                    var $list = $("<ul></ul>");
266                    $list.addClass("blipsContainer");
267                    for (var i = 0; i < pluginData.totalFeatureCount; i++) {
268                        // Counter style 1 has no numbers, while 2 does
269                        var counter;
270                        if (options.counterStyle == 2)
271                            counter = "";
272                        else
273                            counter = i+1;
274
275                        // Build the DOM for the blip list
276                        var $blip = $("<div>"+counter+"</div>");
277                        $blip.addClass("blip");
278                        $blip.css("cursor","pointer");
279                        $blip.attr("id","blip_"+(i+1));
280                        var $listEntry = $("<li></li>");
281                        $listEntry.append($blip);
282                        $listEntry.css("float","left");
283                        $listEntry.css("list-style-type","none");
284                        $list.append($listEntry);
285                    }
286                    // add the blip list and then make sure it's visible
287                    $(pluginData.containerIDTag).append($list);
288                    $list.hide().show();
289                }
290            }
291
292            // Move the highlighted blip to the currently centered feature
293            function changeBlip(oldCenter, newCenter)
294            {
295                // get selectors for the two blips
296                var $blipsContainer = pluginData.featuresContainer.find(".blipsContainer");
297                var $oldCenter = $blipsContainer.find("#blip_"+oldCenter);
298                var $newCenter = $blipsContainer.find("#blip_"+newCenter);
299
300                // change classes
301                $oldCenter.removeClass("blipSelected");
302                $newCenter.addClass("blipSelected");
303            }
304
305            /**
306             * This function will set the autoplay for the carousel to
307             * automatically rotate it given the time in the options
308             */
309            function autoPlay() {
310                // clear the timeout var if it exists
311                if (pluginData.timeoutVar != null) {
312                    pluginData.timeoutVar = clearTimeout(pluginData.timeoutVar);
313                }
314
315                // set interval for moving if autoplay is set
316                if (options.autoPlay != 0) {
317                    var autoTime = (Math.abs(options.autoPlay) < options.carouselSpeed) ? options.carouselSpeed : Math.abs(options.autoPlay);
318                    pluginData.timeoutVar = setTimeout(function () {
319                        if (options.autoPlay > 0)
320                            initiateMove(true,1);
321                        else if (options.autoPlay < 0)
322                            initiateMove(false,1);
323                    }, autoTime);
324                }
325            }
326
327            // This is a helper function for the animateFeature function that
328            // will update the positions of all the features based on the direction
329            function rotatePositions(direction) {
330                $.each(pluginData.featuresArray, function () {
331                    var newPos;
332                    if (direction == false) {
333                        newPos = getNextNum($(this).data().position);
334                    } else {
335                        newPos = getPreviousNum($(this).data().position);
336                    }
337                    $(this).data('position',newPos);
338                });
339            }
340
341            /**
342             * This function is used to animate the given feature to the given
343             * location. Valid locations are "left", "right", "center", "hidden"
344             */
345            function animateFeature($feature, direction)
346            {
347                var new_width, new_height, new_top, new_left, new_zindex, new_padding, new_fade;
348
349                // Determine the old and new positions of the feature
350                var oldPosition = $feature.data('position');
351                var newPosition;
352                if (direction == true)
353                    newPosition = getPreviousNum(oldPosition);
354                else
355                    newPosition = getNextNum(oldPosition);
356
357                // Caculate new new css values depending on where the feature will be located
358                if (newPosition == 1) {
359                    new_width = pluginData.largeFeatureWidth;
360                    new_height = pluginData.largeFeatureHeight;
361                    new_top = options.topPadding;
362                    new_zindex = $feature.css("z-index");
363                    new_left = (pluginData.containerWidth / 2) - (pluginData.largeFeatureWidth / 2) - (pluginData.borderWidth / 2);
364                    new_fade = 1.0;
365                } else {
366                    new_width = pluginData.smallFeatureWidth;
367                    new_height = pluginData.smallFeatureHeight;
368                    new_top = options.smallFeatureOffset + options.topPadding;
369                    new_zindex = 1;
370                    new_fade = 0.4;
371                    // some info is different for the left, right, and hidden positions
372                    // left
373                    if (newPosition == pluginData.totalFeatureCount) {
374                        new_left = options.sidePadding;
375                    // right
376                    } else if (newPosition == 2) {
377                        new_left = pluginData.containerWidth - pluginData.smallFeatureWidth - options.sidePadding - pluginData.borderWidth;
378                    // hidden
379                    } else {
380                        new_left = (pluginData.containerWidth / 2) - (pluginData.smallFeatureWidth / 2) - (pluginData.borderWidth / 2);
381                        new_fade = 0;
382                    }
383                }
384                // This code block takes care of hiding the feature information if the feature is
385                // NO LONGER going to be in the center
386                if (newPosition != 1) {
387                    // Slide up the story information
388                    $feature.find("div")
389                        .hide();
390                }
391
392                // Animate the feature div to its new location
393                $feature
394                    .animate(
395                        {
396                            width: new_width,
397                            height: new_height,
398                            top: new_top,
399                            left: new_left,
400                            opacity: new_fade
401                        },
402                        options.carouselSpeed,
403                        options.animationEasing,
404                        function () {
405                            // Take feature info out of hiding if new position is center
406                            if (newPosition == 1) {
407                                // fade in the feature information
408                                $feature.find("div")
409                                    .fadeTo("fast",0.85);
410                            }
411                            // decrement the animation queue
412                            pluginData.rotationsRemaining = pluginData.rotationsRemaining - 1;
413                            // have to change the z-index after the animation is done
414                            $feature.css("z-index", new_zindex);
415                            // change blips if using them
416                            if (options.counterStyle == 1 || options.counterStyle == 2) {
417                                if (newPosition == 1) {
418                                    // figure out what item was just in the center, and what item is now in the center
419                                    var newCenterItemNum = pluginData.featuresContainer.children("div").index($feature) + 1;
420                                    var oldCenterItemNum;
421                                    if (direction == false)
422                                        oldCenterItemNum = getNextNum(newCenterItemNum);
423                                    else
424                                        oldCenterItemNum = getPreviousNum(newCenterItemNum);
425                                    // now change the active blip
426                                    changeBlip(oldCenterItemNum, newCenterItemNum);
427                                }
428                            }
429
430                            // did all the the animations finish yet?
431                            var divide = pluginData.rotationsRemaining / pluginData.itemsToAnimate;
432                            if (divide % 1 == 0) {
433                                // if so, set moving to false...
434                                pluginData.currentlyMoving = false;
435                                // change positions for all items...
436                                rotatePositions(direction);
437
438                                // and move carousel again if queue is not empty
439                                if (pluginData.rotationsRemaining > 0)
440                                    move(direction);
441                            }
442
443                            // call autoplay again
444                            autoPlay();
445                        }
446                    )
447                    // select the image within the feature
448                    .find("img:first")
449                        // animate its size down
450                        .animate({
451                            width: new_width,
452                            height: new_height
453                        },
454                        options.carouselSpeed,
455                        options.animationEasing)
456                    .end();
457            }
458
459            /**
460             * move the carousel to the left or to the right. The features that
461             * will move into the four positions are calculated and then animated
462             * rotate to the RIGHT when direction is TRUE and
463             * rotate to the LEFT when direction is FALSE
464             */
465            function move(direction)
466            {
467                // Set the carousel to currently moving
468                pluginData.currentlyMoving = true;
469
470                // Obtain the new feature positions based on the direction that the carousel is moving
471                var $newCenter, $newLeft, $newRight, $newHidden;
472                if (direction == true) {
473                    // Shift features to the left
474                    $newCenter = getContainer(getNextNum(pluginData.currentCenterNum));
475                    $newLeft = getContainer(pluginData.currentCenterNum);
476                    $newRight = getContainer(getNextNum(getNextNum(pluginData.currentCenterNum)));
477                    $newHidden = getContainer(getPreviousNum(pluginData.currentCenterNum));
478                    pluginData.currentCenterNum = getNextNum(pluginData.currentCenterNum);
479                } else {
480                    $newCenter = getContainer(getPreviousNum(pluginData.currentCenterNum));
481                    $newLeft = getContainer(getPreviousNum(getPreviousNum(pluginData.currentCenterNum)));
482                    $newRight = getContainer(pluginData.currentCenterNum);
483                    $newHidden = getContainer(getNextNum(pluginData.currentCenterNum));
484                    pluginData.currentCenterNum = getPreviousNum(pluginData.currentCenterNum);
485                }
486
487                // The z-index must be set before animations take place for certain movements
488                // this makes the animations look nicer
489                if (direction) {
490                    $newLeft.css("z-index", 3);
491                } else {
492                    $newRight.css("z-index", 3);
493                }
494                $newCenter.css("z-index", 4);
495
496                // Animate the features into their new positions
497                animateFeature($newLeft, direction);
498                animateFeature($newCenter, direction);
499                animateFeature($newRight, direction);
500                // Only want to animate the "hidden" feature if there are more than three
501                if (pluginData.totalFeatureCount > 3) {
502                    animateFeature($newHidden, direction);
503                }
504            }
505
506            // This is used to relegate carousel movement throughout the plugin
507            // It will only initiate a move if the carousel isn't currently moving
508            // It will set the animation queue to the number of rotations given
509            function initiateMove(direction, rotations) {
510                if (pluginData.currentlyMoving == false) {
511                    var queue = rotations * pluginData.itemsToAnimate;
512                    pluginData.rotationsRemaining = queue;
513                    move(direction);
514                }
515            }
516
517            /**
518             * This will find the shortest distance to travel the carousel from
519             * one position to another position. It will return the shortest distance
520             * in number form, and will be positive to go to the right and negative for left
521             */
522            function findShortestDistance(from, to) {
523                var goingToLeft = 1, goingToRight = 1, tracker;
524                tracker = from;
525                // see how long it takes to go to the left
526                while ((tracker = getPreviousNum(tracker)) != to) {
527                    goingToLeft++;
528                }
529
530                tracker = from;
531                // see how long it takes to to to the right
532                while ((tracker = getNextNum(tracker)) != to) {
533                    goingToRight++;
534                }
535
536                // whichever is shorter
537                return (goingToLeft < goingToRight) ? goingToLeft*-1 : goingToRight;
538            }
539
540            // Move to the left if left button clicked
541            $(".leftButton").click(function () {
542                initiateMove(false,1);
543            });
544
545            // Move to right if right button clicked
546            $(".rightButton").click(function () {
547                initiateMove(true,1);
548            });
549
550            // These are the click and hover events for the features
551            pluginData.featuresContainer.children("div")
552                .click(function () {
553                    var position = $(this).data('position');
554                    if (position == 2) {
555                        initiateMove(true,1);
556                    } else if (position == pluginData.totalFeatureCount) {
557                        initiateMove(false,1);
558                    }
559                })
560                .mouseover(function () {
561                    if (pluginData.currentlyMoving == false) {
562                        var position = $(this).data('position');
563                        if (position == 2 || position == pluginData.totalFeatureCount) {
564                            $(this).css("opacity",0.8);
565                        }
566                    }
567                })
568                .mouseout(function () {
569                    if (pluginData.currentlyMoving == false) {
570                        var position = $(this).data('position');
571                        if (position == 2 || position == pluginData.totalFeatureCount) {
572                            $(this).css("opacity",0.4);
573                        }
574                    }
575                });
576
577            // Add event listener to all clicks within the features container
578            // This is done to disable any links that aren't within the center feature
579            $("a", pluginData.containerIDTag).live("click", function (event) {
580                // travel up to the container
581                var $parents = $(this).parentsUntil(pluginData.containerIDTag);
582                // now check each of the feature divs within it
583                $parents.each(function () {
584                    var position = $(this).data('position');
585                    // if there are more than just feature divs within the container, they will
586                    // not have a position and it may come back as undefined. Throw these out
587                    if (position != undefined) {
588                        // if any of the links on a feature OTHER THAN the center feature were clicked,
589                        // initiate a carousel move but then throw the link action away
590                        // if the position WAS the center (i.e. 1), then do nothing and let the link pass
591                        if (position != 1) {
592                            if (position == pluginData.totalFeatureCount) {
593                                initiateMove(false,1);
594                            } else if (position == 2) {
595                                initiateMove(true,1);
596                            }
597                            event.preventDefault();
598                            return false;
599                        }
600                    }
601                });
602            });
603
604            $(".blip").live("click",function () {
605                // grab the position # that was clicked
606                var goTo = $(this).attr("id").substring(5);
607                // find out where that feature # actually is in the carousel right now
608                var whereIsIt = pluginData.featuresContainer.children("div").eq(goTo-1).data('position');
609                // which feature # is currently in the center
610                var currentlyAt = pluginData.currentCenterNum;
611                // if the blip was clicked for the current center feature, do nothing
612                if (goTo != currentlyAt) {
613                    // find the shortest distance to move the carousel
614                    var shortest = findShortestDistance(1, whereIsIt);
615                    // initiate a move in that direction with given number of rotations
616                    if (shortest < 0) {
617                        initiateMove(false,(shortest*-1));
618                    } else {
619                        initiateMove(true,shortest);
620                    }
621                }
622
623            });
624        });
625    };
626
627    $.fn.featureCarousel.defaults = {
628        // If zero, take original width and height of image
629        // If between 0 and 1, multiply by original width and height (to get smaller size)
630        // If greater than one, use in place of original pixel dimensions
631        largeFeatureWidth :     0,
632        largeFeatureHeight:		0,
633        smallFeatureWidth:      0,
634        smallFeatureHeight:		0,
635        // how much to pad the top of the carousel
636        topPadding:             20,
637        // spacing between the sides of the container (pixels)
638        sidePadding:            30,
639        // the additional offset to pad the side features from the top of the carousel
640        smallFeatureOffset:		50,
641        // indicates which feature to start the carousel at
642        startingFeature:        1,
643        // speed in milliseconds it takes to rotate the carousel
644        carouselSpeed:          1000,
645        // time in milliseconds to set interval to autorotate the carousel
646        // set to zero to disable it, negative to go left
647        autoPlay:               0,
648        // set to true to enable the creation of blips to indicate how many
649        // features there are
650        counterStyle:           1,
651        // true to preload all images in the carousel before displaying anything
652        preload:                true,
653        // Will only display this many features in the carousel
654        // set to zero to disable
655        displayCutoff:          0,
656        // an easing can be specified for the animation of the carousel
657        animationEasing:        'swing'
658    };
659
660})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.