PageSourceSearch

https://odkb.ru/js/jquery.smoothDivScroll-1.3.js

js odkb.ru collected 2026-10-03 21:42:19 UTC 65,414 bytes, 1,436 lines download raw bytes

1/*
2 * jQuery SmoothDivScroll 1.3
3 *
4 * Copyright (c) 2013 Thomas Kahn
5 * Licensed under the GPL license.
6 *
7 * http://www.smoothdivscroll.com/
8 *
9 * Depends:
10 * jquery-1.10.2.min.js
11   Please use https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js
12   ...or later
13
14 * jquery-ui-1.10.3.custom.min
15   Make your own custom download at http://jqueryui.com/download.
16   First deselect all components. Then check just "Widget" and "Effects Core".
17   Download the file and put it in your javascript folder.
18
19 * jquery.mousewheel.min.js
20   Used for mousewheel functionality.
21   Download the latest version at https://github.com/brandonaaron/jquery-mousewheel
22 *
23
24 * jquery.kinetic.min.js
25   Used for scrolling by dragging, mainly used on touch devices.
26   Download the latest version at https://github.com/davetayls/jquery.kinetic
27 *
28 */
29(function($) {
30
31    $.widget("thomaskahn.smoothDivScroll", {
32        // Default options
33        options: {
34            // Classes for elements added by Smooth Div Scroll
35            scrollingHotSpotLeftClass: "scrollingHotSpotLeft", // String
36            scrollingHotSpotRightClass: "scrollingHotSpotRight", // String
37            scrollingHotSpotLeftVisibleClass: "scrollingHotSpotLeftVisible", // String
38            scrollingHotSpotRightVisibleClass: "scrollingHotSpotRightVisible", // String
39            scrollableAreaClass: "scrollableArea", // String
40            scrollWrapperClass: "scrollWrapper", // String
41
42            // Misc settings
43            hiddenOnStart: false, // Boolean
44            getContentOnLoad: {}, // Object
45            countOnlyClass: "", // String
46            startAtElementId: "", // String
47
48            // Hotspot scrolling
49            hotSpotScrolling: true, // Boolean
50            hotSpotScrollingStep: 1500, // Pixels
51            hotSpotScrollingInterval: 10, // Milliseconds
52            hotSpotMouseDownSpeedBooster: 3, // Integer
53            visibleHotSpotBackgrounds: "hover", // always, onStart, hover or empty (no visible hotspots)
54            hotSpotsVisibleTime: 5000, // Milliseconds
55            easingAfterHotSpotScrolling: true, // Boolean
56            easingAfterHotSpotScrollingDistance: 10, // Pixels
57            easingAfterHotSpotScrollingDuration: 300, // Milliseconds
58            easingAfterHotSpotScrollingFunction: "easeOutQuart", // String
59
60            // Mousewheel scrolling
61            mousewheelScrolling: "", // vertical, horizontal, allDirections or empty (no mousewheel scrolling) String
62            mousewheelScrollingStep: 70, // Pixels
63            easingAfterMouseWheelScrolling: true, // Boolean
64            easingAfterMouseWheelScrollingDuration: 300, // Milliseconds
65            easingAfterMouseWheelScrollingFunction: "easeOutQuart", // String
66
67            // Manual scrolling (hotspot and/or mousewheel scrolling)
68            manualContinuousScrolling: false, // Boolean
69
70            // Autoscrolling
71            autoScrollingMode: "", // always, onStart or empty (no auto scrolling) String
72            autoScrollingDirection: "endlessLoopRight", // right, left, backAndForth, endlessLoopRight, endlessLoopLeft String
73            autoScrollingStep: 1, // Pixels
74            autoScrollingInterval: 10, // Milliseconds
75
76            // Touch scrolling
77            touchScrolling: false,
78
79            // Easing for when the scrollToElement method is used
80            scrollToAnimationDuration: 1000, // Milliseconds
81            scrollToEasingFunction: "easeOutQuart" // String
82        },
83        _create: function() {
84            var self = this,
85                o = this.options,
86                el = this.element;
87
88            // Create variables for any existing or not existing
89            // scroller elements on the page.
90            el.data("scrollWrapper", el.find("." + o.scrollWrapperClass));
91            el.data("scrollingHotSpotRight", el.find("." + o.scrollingHotSpotRightClass));
92            el.data("scrollingHotSpotLeft", el.find("." + o.scrollingHotSpotLeftClass));
93            el.data("scrollableArea", el.find("." + o.scrollableAreaClass));
94
95            // Check which elements are already present on the page.
96            // Create any elements needed by the plugin if
97            // the user hasn't already created them.
98
99            // First detach any present hot spots
100            if (el.data("scrollingHotSpotRight").length > 0) {
101
102                el.data("scrollingHotSpotRight").detach();
103            }
104            if (el.data("scrollingHotSpotLeft").length > 0) {
105
106                el.data("scrollingHotSpotLeft").detach();
107            }
108
109            // Both the scrollable area and the wrapper are missing
110            if (el.data("scrollableArea").length === 0 && el.data("scrollWrapper").length === 0) {
111                el.wrapInner("<div class='" + o.scrollableAreaClass + "'>").wrapInner("<div class='" + o.scrollWrapperClass + "'>");
112
113                el.data("scrollWrapper", el.find("." + o.scrollWrapperClass));
114                el.data("scrollableArea", el.find("." + o.scrollableAreaClass));
115            }
116            // Only the wrapper is missing
117            else if (el.data("scrollWrapper").length === 0) {
118                el.wrapInner("<div class='" + o.scrollWrapperClass + "'>");
119                el.data("scrollWrapper", el.find("." + o.scrollWrapperClass));
120            }
121            // Only the scrollable area is missing
122            else if (el.data("scrollableArea").length === 0) {
123                el.data("scrollWrapper").wrapInner("<div class='" + o.scrollableAreaClass + "'>");
124                el.data("scrollableArea", el.find("." + o.scrollableAreaClass));
125            }
126
127            // Put the right and left hot spot back into the scroller again
128            // or create them if they where not present from the beginning.
129            if (el.data("scrollingHotSpotRight").length === 0) {
130                el.prepend("<div class='" + o.scrollingHotSpotRightClass + "'></div>");
131                el.data("scrollingHotSpotRight", el.find("." + o.scrollingHotSpotRightClass));
132            } else {
133                el.prepend(el.data("scrollingHotSpotRight"));
134            }
135
136            if (el.data("scrollingHotSpotLeft").length === 0) {
137                el.prepend("<div class='" + o.scrollingHotSpotLeftClass + "'></div>");
138                el.data("scrollingHotSpotLeft", el.find("." + o.scrollingHotSpotLeftClass));
139            } else {
140                el.prepend(el.data("scrollingHotSpotLeft"));
141            }
142
143            // Create variables in the element data storage
144            el.data("speedBooster", 1);
145            el.data("scrollXPos", 0);
146            el.data("hotSpotWidth", '300');
147            el.data("scrollableAreaWidth", 0);
148            el.data("startingPosition", 0);
149            el.data("rightScrollingInterval", null);
150            el.data("leftScrollingInterval", null);
151            el.data("autoScrollingInterval", null);
152            el.data("hideHotSpotBackgroundsInterval", null);
153            el.data("previousScrollLeft", 0);
154            el.data("pingPongDirection", "right");
155            el.data("getNextElementWidth", true);
156            el.data("swapAt", null);
157            el.data("startAtElementHasNotPassed", true);
158            el.data("swappedElement", null);
159            el.data("originalElements", el.data("scrollableArea").children(o.countOnlyClass));
160            el.data("visible", true);
161            el.data("enabled", true);
162            el.data("scrollableAreaHeight", el.data("scrollableArea").height());
163            el.data("scrollerOffset", el.offset());
164
165            /*****************************************
166			SET UP EVENTS FOR TOUCH SCROLLING
167			*****************************************/
168            if (o.touchScrolling && el.data("enabled")) {
169                // Use jquery.kinetic.js for touch scrolling
170                // Vertical scrolling disabled
171                el.data("scrollWrapper").kinetic({
172                    y: false,
173                    moved: function(settings) {
174                        if (o.manualContinuousScrolling) {
175                            if (el.data("scrollWrapper").scrollLeft() <= 0) {
176                                self._checkContinuousSwapLeft();
177                            } else {
178                                self._checkContinuousSwapRight();
179                            }
180                        }
181
182                        // Callback
183                        self._trigger("touchMoved");
184                    },
185                    stopped: function(settings) {
186                        // Stop any ongoing animations
187                        el.data("scrollWrapper").stop(true, false);
188
189                        // Stop any ongoing auto scrolling
190                        self.stopAutoScrolling();
191
192                        // Callback
193                        self._trigger("touchStopped");
194                    }
195                });
196            }
197
198            /*****************************************
199			SET UP EVENTS FOR SCROLLING RIGHT
200			*****************************************/
201            // Check the mouse X position and calculate
202            // the relative X position inside the right hotspot
203            el.data("scrollingHotSpotRight").bind("mousemove", function(e) {
204                if (o.hotSpotScrolling) {
205                    //var x = e.pageX - $(this).offset().left;
206                    var x = 1;
207                    el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.hotSpotScrollingStep));
208
209                    // If the position is less then 1, it's set to 1
210                    if (el.data("scrollXPos") === Infinity || el.data("scrollXPos") < 1) {
211                        el.data("scrollXPos", 1);
212                    }
213                }
214            });
215
216            // Mouseover right hotspot - scrolling
217            el.data("scrollingHotSpotRight").bind("mouseover", function() {
218                if (o.hotSpotScrolling) {
219                    // Stop any ongoing animations
220                    el.data("scrollWrapper").stop(true, false);
221
222                    // Stop any ongoing auto scrolling
223                    self.stopAutoScrolling();
224
225                    // Start the scrolling interval
226                    el.data("rightScrollingInterval", setInterval(function() {
227                        if (el.data("scrollXPos") > 0 && el.data("enabled")) {
228                            el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (el.data("scrollXPos") * el.data("speedBooster")));
229
230                            if (o.manualContinuousScrolling) {
231                                self._checkContinuousSwapRight();
232                            }
233
234                            self._showHideHotSpots();
235                        }
236                    }, o.hotSpotScrollingInterval));
237
238                    // Callback
239                    self._trigger("mouseOverRightHotSpot");
240                }
241            });
242
243            // Mouseout right hotspot - stop scrolling
244            el.data("scrollingHotSpotRight").bind("mouseout", function() {
245                if (o.hotSpotScrolling) {
246                    clearInterval(el.data("rightScrollingInterval"));
247                    el.data("scrollXPos", 0);
248
249                    // Easing out after scrolling
250                    if (o.easingAfterHotSpotScrolling && el.data("enabled")) {
251                        el.data("scrollWrapper").animate({
252                            scrollLeft: el.data("scrollWrapper").scrollLeft() + o.easingAfterHotSpotScrollingDistance
253                        }, {
254                            duration: o.easingAfterHotSpotScrollingDuration,
255                            easing: o.easingAfterHotSpotScrollingFunction
256                        });
257                    }
258                }
259            });
260
261            // mousedown right hotspot (add scrolling speed booster)
262            el.data("scrollingHotSpotRight").bind("mousedown", function() {
263                el.data("speedBooster", o.hotSpotMouseDownSpeedBooster);
264            });
265
266            // mouseup anywhere (stop boosting the scrolling speed)
267            $("body").bind("mouseup", function() {
268                el.data("speedBooster", 1);
269            });
270
271            /*****************************************
272			SET UP EVENTS FOR SCROLLING LEFT
273			*****************************************/
274            // Check the mouse X position and calculate
275            // the relative X position inside the left hotspot
276            el.data("scrollingHotSpotLeft").bind("mousemove", function(e) {
277                if (o.hotSpotScrolling) {
278                    //var x = el.data("hotSpotWidth") - (e.pageX - $(this).offset().left);
279                    var x = 1;
280
281                    el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.hotSpotScrollingStep));
282                    // If the position is less then 1, it's set to 1
283                    if (el.data("scrollXPos") === Infinity || el.data("scrollXPos") < 1) {
284                        el.data("scrollXPos", 1);
285                    }
286                }
287            });
288
289            // Mouseover left hotspot
290            el.data("scrollingHotSpotLeft").bind("mouseover", function() {
291                if (o.hotSpotScrolling) {
292                    // Stop any ongoing animations
293                    el.data("scrollWrapper").stop(true, false);
294
295                    // Stop any ongoing auto scrolling
296                    self.stopAutoScrolling();
297
298                    el.data("leftScrollingInterval", setInterval(function() {
299                        if (el.data("scrollXPos") > 0 && el.data("enabled")) {
300                            el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (el.data("scrollXPos") * el.data("speedBooster")));
301
302                            if (o.manualContinuousScrolling) {
303                                self._checkContinuousSwapLeft();
304                            }
305
306                            self._showHideHotSpots();
307                        }
308                    }, o.hotSpotScrollingInterval));
309
310                    // Callback
311                    self._trigger("mouseOverLeftHotSpot");
312                }
313            });
314
315            // mouseout left hotspot
316            el.data("scrollingHotSpotLeft").bind("mouseout", function() {
317                if (o.hotSpotScrolling) {
318                    clearInterval(el.data("leftScrollingInterval"));
319                    el.data("scrollXPos", 0);
320
321                    // Easing out after scrolling
322                    if (o.easingAfterHotSpotScrolling && el.data("enabled")) {
323                        el.data("scrollWrapper").animate({
324                            scrollLeft: el.data("scrollWrapper").scrollLeft() - o.easingAfterHotSpotScrollingDistance
325                        }, {
326                            duration: o.easingAfterHotSpotScrollingDuration,
327                            easing: o.easingAfterHotSpotScrollingFunction
328                        });
329                    }
330                }
331            });
332
333            // mousedown left hotspot (add scrolling speed booster)
334            el.data("scrollingHotSpotLeft").bind("mousedown", function() {
335                el.data("speedBooster", o.hotSpotMouseDownSpeedBooster);
336            });
337
338            /*****************************************
339			SET UP EVENT FOR MOUSEWHEEL SCROLLING
340			*****************************************/
341            el.data("scrollableArea").mousewheel(function(event, delta, deltaX, deltaY) {
342
343                if (el.data("enabled") && o.mousewheelScrolling.length > 0) {
344                    var pixels;
345
346                    // Can be either positive or negative
347                    // Is multiplied/inverted by minus one since you want it to scroll
348                    // left when moving the wheel down/right and right when moving the wheel up/left
349                    if (o.mousewheelScrolling === "vertical" && deltaY !== 0) {
350                        // Stop any ongoing auto scrolling if it's running
351                        self.stopAutoScrolling();
352                        event.preventDefault();
353                        pixels = Math.round((o.mousewheelScrollingStep * deltaY) * -1);
354                        self.move(pixels);
355                    } else if (o.mousewheelScrolling === "horizontal" && deltaX !== 0) {
356                        // Stop any ongoing auto scrolling if it's running
357                        self.stopAutoScrolling();
358                        event.preventDefault();
359                        pixels = Math.round((o.mousewheelScrollingStep * deltaX) * -1);
360                        self.move(pixels);
361                    } else if (o.mousewheelScrolling === "allDirections") {
362                        // Stop any ongoing auto scrolling if it's running
363                        self.stopAutoScrolling();
364                        event.preventDefault();
365                        pixels = Math.round((o.mousewheelScrollingStep * delta) * -1);
366                        self.move(pixels);
367                    }
368
369                }
370            });
371
372            // Capture and disable mousewheel events when the pointer
373            // is over any of the hotspots
374            if (o.mousewheelScrolling) {
375                el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).mousewheel(function(event) {
376                    event.preventDefault();
377                });
378            }
379
380            /*****************************************
381			SET UP EVENT FOR RESIZING THE BROWSER WINDOW
382			*****************************************/
383            $(window).bind("resize", function() {
384                self._showHideHotSpots();
385                self._trigger("windowResized");
386            });
387
388            /*****************************************
389			FETCHING CONTENT ON INITIALIZATION
390			*****************************************/
391            // If getContentOnLoad is present in the options,
392            // sort out the method and parameters and get the content
393
394            if (!(jQuery.isEmptyObject(o.getContentOnLoad))) {
395                self[o.getContentOnLoad.method](o.getContentOnLoad.content, o.getContentOnLoad.manipulationMethod, o.getContentOnLoad.addWhere, o.getContentOnLoad.filterTag);
396            }
397
398            // Should it be hidden on start?
399            if (o.hiddenOnStart) {
400                self.hide();
401            }
402
403            /*****************************************
404			AUTOSCROLLING
405			*****************************************/
406            // The $(window).load event handler is used because the width of the elements are not calculated
407            // properly until then, at least not in Google Chrome. The start of the auto scrolling and the
408            // setting of the hotspot backgrounds is started here as well for the same reason.
409            // If the auto scrolling is not started in $(window).load, it won't start because it
410            // will interpret the scrollable areas as too short.
411            $(window).load(function() {
412
413                // If scroller is not hidden, recalculate the scrollable area
414                if (!(o.hiddenOnStart)) {
415                    self.recalculateScrollableArea();
416                }
417
418                // Autoscrolling is active
419                if ((o.autoScrollingMode.length > 0) && !(o.hiddenOnStart)) {
420                    self.startAutoScrolling();
421                }
422
423                // If the user wants to have visible hotspot backgrounds,
424                // here is where it's taken care of
425                if (o.autoScrollingMode !== "always") {
426
427                    switch (o.visibleHotSpotBackgrounds) {
428                        case "always":
429                            self.showHotSpotBackgrounds();
430                            break;
431                        case "onStart":
432                            self.showHotSpotBackgrounds();
433                            el.data("hideHotSpotBackgroundsInterval", setTimeout(function() {
434                                self.hideHotSpotBackgrounds(250);
435                            }, o.hotSpotsVisibleTime));
436                            break;
437                        case "hover":
438                            el.mouseenter(function(event) {
439                                if (o.hotSpotScrolling) {
440                                    event.stopPropagation();
441                                    self.showHotSpotBackgrounds(250);
442                                }
443                            }).mouseleave(function(event) {
444                                if (o.hotSpotScrolling) {
445                                    event.stopPropagation();
446                                    self.hideHotSpotBackgrounds(250);
447                                }
448                            });
449                            break;
450                        default:
451                            break;
452                    }
453                }
454
455                self._showHideHotSpots();
456
457                self._trigger("setupComplete");
458
459            });
460
461        },
462        /**********************************************************
463		_init
464		**********************************************************/
465        // When the contents of the scrollable area is changed outside the widget,
466        // the widget must be reinitilaized.
467        // This code is run every time the widget is called without arguments
468        _init: function() {
469            var self = this,
470                el = this.element;
471
472            // Recalculate the total width of the elements inside the scrollable area
473            self.recalculateScrollableArea();
474
475            // Determine which hotspots to show
476            self._showHideHotSpots();
477
478            // Trigger callback
479            self._trigger("initializationComplete");
480        },
481        /**********************************************************
482		Override _setOption and handle altered options
483		**********************************************************/
484        _setOption: function(key, value) {
485            var self = this,
486                o = this.options,
487                el = this.element;
488
489            // Update option
490            o[key] = value;
491
492            if (key === "hotSpotScrolling") {
493                // Handler if the option hotSpotScrolling is altered
494                if (value === true) {
495                    self._showHideHotSpots();
496                } else {
497                    el.data("scrollingHotSpotLeft").hide();
498                    el.data("scrollingHotSpotRight").hide();
499                }
500            } else if (key === "autoScrollingStep" ||
501                // Make sure that certain values are integers, otherwise
502                // they will summon bad spirits in the plugin
503                key === "easingAfterHotSpotScrollingDistance" ||
504                key === "easingAfterHotSpotScrollingDuration" ||
505                key === "easingAfterMouseWheelScrollingDuration") {
506                o[key] = parseInt(value, 10);
507            } else if (key === "autoScrollingInterval") {
508                // Handler if the autoScrollingInterval is altered
509                o[key] = parseInt(value, 10);
510                self.startAutoScrolling();
511            }
512
513        },
514        /**********************************************************
515		Hotspot functions
516		**********************************************************/
517        showHotSpotBackgrounds: function(fadeSpeed) {
518
519            // Alter the CSS (SmoothDivScroll.css) if you want to customize
520            // the look'n'feel of the visible hotspots
521            var self = this,
522                el = this.element,
523                o = this.options;
524
525            // Fade in the hotspot backgrounds
526            if (fadeSpeed !== undefined) {
527                // Before the fade-in starts, we need to make sure the opacity is zero
528                //el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).css("opacity", "0.0");
529
530                el.data("scrollingHotSpotLeft").addClass(o.scrollingHotSpotLeftVisibleClass);
531                el.data("scrollingHotSpotRight").addClass(o.scrollingHotSpotRightVisibleClass);
532
533                // Fade in the hotspots
534                el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).fadeTo(fadeSpeed, 0.35);
535            }
536            // Don't fade, just show them
537            else {
538
539                // The left hotspot
540                el.data("scrollingHotSpotLeft").addClass(o.scrollingHotSpotLeftVisibleClass);
541                el.data("scrollingHotSpotLeft").removeAttr("style");
542
543                // The right hotspot
544                el.data("scrollingHotSpotRight").addClass(o.scrollingHotSpotRightVisibleClass);
545                el.data("scrollingHotSpotRight").removeAttr("style");
546            }
547
548            self._showHideHotSpots();
549
550        },
551        hideHotSpotBackgrounds: function(fadeSpeed) {
552            var el = this.element,
553                o = this.options;
554
555            // Fade out the hotspot backgrounds
556            if (fadeSpeed !== undefined) {
557
558                // Fade out the left hotspot
559                el.data("scrollingHotSpotLeft").fadeTo(fadeSpeed, 0.0, function() {
560                    el.data("scrollingHotSpotLeft").removeClass(o.scrollingHotSpotLeftVisibleClass);
561                });
562
563                // Fade out the right hotspot
564                el.data("scrollingHotSpotRight").fadeTo(fadeSpeed, 0.0, function() {
565                    el.data("scrollingHotSpotRight").removeClass(o.scrollingHotSpotRightVisibleClass);
566                });
567
568            }
569            // Don't fade, just hide them
570            else {
571                el.data("scrollingHotSpotLeft").removeClass(o.scrollingHotSpotLeftVisibleClass).removeAttr("style");
572                el.data("scrollingHotSpotRight").removeClass(o.scrollingHotSpotRightVisibleClass).removeAttr("style");
573            }
574
575        },
576        // Function for showing and hiding hotspots depending on the
577        // offset of the scrolling
578        _showHideHotSpots: function() {
579            var self = this,
580                el = this.element,
581                o = this.options;
582
583            // Hot spot scrolling is not enabled so show no hot spots
584            if (!(o.hotSpotScrolling)) {
585                el.data("scrollingHotSpotLeft").hide();
586                el.data("scrollingHotSpotRight").hide();
587            } else {
588
589                // If the manual continuous scrolling option is set show both
590                if (o.hotSpotScrolling && o.autoScrollingMode !== "always" && el.data("autoScrollingInterval") !== null) {
591                    el.data("scrollingHotSpotLeft").show();
592                    el.data("scrollingHotSpotRight").show();
593                }
594                // Autoscrolling not set to always and hotspot scrolling enabled.
595                // Regular hot spot scrolling.
596                else if (o.autoScrollingMode !== "always" && o.hotSpotScrolling) {
597                    // If the scrollable area is shorter than the scroll wrapper, both hotspots
598                    // should be hidden
599                    if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth())) {
600                        el.data("scrollingHotSpotLeft").hide();
601                        el.data("scrollingHotSpotRight").hide();
602                    }
603                    // When you can't scroll further left the left scroll hotspot should be hidden
604                    // and the right hotspot visible.
605                    else if (el.data("scrollWrapper").scrollLeft() === 0) {
606                        el.data("scrollingHotSpotLeft").hide();
607                        el.data("scrollingHotSpotRight").show();
608                        // Callback
609                        self._trigger("scrollerLeftLimitReached");
610                        // Clear interval
611                        clearInterval(el.data("leftScrollingInterval"));
612                        el.data("leftScrollingInterval", null);
613                    }
614                    // When you can't scroll further right
615                    // the right scroll hotspot should be hidden
616                    // and the left hotspot visible
617                    else if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth() + el.data("scrollWrapper").scrollLeft())) {
618                        el.data("scrollingHotSpotLeft").show();
619                        el.data("scrollingHotSpotRight").hide();
620                        // Callback
621                        self._trigger("scrollerRightLimitReached");
622                        // Clear interval
623                        clearInterval(el.data("rightScrollingInterval"));
624                        el.data("rightScrollingInterval", null);
625                    }
626                    // If you are somewhere in the middle of your
627                    // scrolling, both hotspots should be visible
628                    else {
629                        el.data("scrollingHotSpotLeft").show();
630                        el.data("scrollingHotSpotRight").show();
631                    }
632                }
633                // If auto scrolling is set to always, there should be no hotspots
634                else {
635                    el.data("scrollingHotSpotLeft").hide();
636                    el.data("scrollingHotSpotRight").hide();
637                }
638            }
639
640        },
641        // Function for calculating the scroll position of a certain element
642        _setElementScrollPosition: function(method, element) {
643            var el = this.element,
644                o = this.options,
645                tempScrollPosition = 0;
646
647            switch (method) {
648                case "first":
649                    el.data("scrollXPos", 0);
650                    return true;
651                case "start":
652                    // Check to see if there is a specified start element in the options
653                    // and that the element exists in the DOM
654                    if (o.startAtElementId !== "") {
655                        if (el.data("scrollableArea").has("#" + o.startAtElementId)) {
656                            tempScrollPosition = $("#" + o.startAtElementId).position().left;
657                            el.data("scrollXPos", tempScrollPosition);
658                            return true;
659                        }
660                    }
661                    return false;
662                case "last":
663                    el.data("scrollXPos", (el.data("scrollableAreaWidth") - el.data("scrollWrapper").innerWidth()));
664                    return true;
665                case "number":
666                    // Check to see that an element number is passed
667                    if (!(isNaN(element))) {
668                        tempScrollPosition = el.data("scrollableArea").children(o.countOnlyClass).eq(element - 1).position().left;
669                        el.data("scrollXPos", tempScrollPosition);
670                        return true;
671                    }
672                    return false;
673                case "id":
674                    // Check that an element id is passed and that the element exists in the DOM
675                    if (element.length > 0) {
676                        if (el.data("scrollableArea").has("#" + element)) {
677                            tempScrollPosition = $("#" + element).position().left;
678                            el.data("scrollXPos", tempScrollPosition);
679                            return true;
680                        }
681                    }
682                    return false;
683                default:
684                    return false;
685            }
686
687        },
688        /**********************************************************
689		Jumping to a certain element
690		**********************************************************/
691        jumpToElement: function(jumpTo, element) {
692            var self = this,
693                el = this.element;
694
695            // Check to see that the scroller is enabled
696            if (el.data("enabled")) {
697                // Get the position of the element to scroll to
698                if (self._setElementScrollPosition(jumpTo, element)) {
699                    // Jump to the element
700                    el.data("scrollWrapper").scrollLeft(el.data("scrollXPos"));
701                    // Check the hotspots
702                    self._showHideHotSpots();
703                    // Trigger the right callback
704                    switch (jumpTo) {
705                        case "first":
706                            self._trigger("jumpedToFirstElement");
707                            break;
708                        case "start":
709                            self._trigger("jumpedToStartElement");
710                            break;
711                        case "last":
712                            self._trigger("jumpedToLastElement");
713                            break;
714                        case "number":
715                            self._trigger("jumpedToElementNumber", null, {
716                                "elementNumber": element
717                            });
718                            break;
719                        case "id":
720                            self._trigger("jumpedToElementId", null, {
721                                "elementId": element
722                            });
723                            break;
724                        default:
725                            break;
726                    }
727
728                }
729            }
730        },
731        /**********************************************************
732		Scrolling to a certain element
733		**********************************************************/
734        scrollToElement: function(scrollTo, element) {
735            var self = this,
736                el = this.element,
737                o = this.options,
738                autoscrollingWasRunning = false;
739
740            if (el.data("enabled")) {
741                // Get the position of the element to scroll to
742                if (self._setElementScrollPosition(scrollTo, element)) {
743                    // Stop any ongoing auto scrolling
744                    if (el.data("autoScrollingInterval") !== null) {
745                        self.stopAutoScrolling();
746                        autoscrollingWasRunning = true;
747                    }
748
749                    // Stop any other running animations
750                    // (clear queue but don't jump to the end)
751                    el.data("scrollWrapper").stop(true, false);
752
753                    // Do the scolling animation
754                    el.data("scrollWrapper").animate({
755                        scrollLeft: el.data("scrollXPos")
756                    }, {
757                        duration: o.scrollToAnimationDuration,
758                        easing: o.scrollToEasingFunction,
759                        complete: function() {
760                            // If auto scrolling was running before, start it again
761                            if (autoscrollingWasRunning) {
762                                self.startAutoScrolling();
763                            }
764
765                            self._showHideHotSpots();
766
767                            // Trigger the right callback
768                            switch (scrollTo) {
769                                case "first":
770                                    self._trigger("scrolledToFirstElement");
771                                    break;
772                                case "start":
773                                    self._trigger("scrolledToStartElement");
774                                    break;
775                                case "last":
776                                    self._trigger("scrolledToLastElement");
777                                    break;
778                                case "number":
779                                    self._trigger("scrolledToElementNumber", null, {
780                                        "elementNumber": element
781                                    });
782                                    break;
783                                case "id":
784                                    self._trigger("scrolledToElementId", null, {
785                                        "elementId": element
786                                    });
787                                    break;
788                                default:
789                                    break;
790                            }
791                        }
792                    });
793                }
794            }
795
796        },
797        move: function(pixels) {
798            var self = this,
799                el = this.element,
800                o = this.options;
801            // clear queue, move to end
802            el.data("scrollWrapper").stop(true, true);
803
804            // Only run this code if it's possible to scroll left or right,
805            if ((pixels < 0 && el.data("scrollWrapper").scrollLeft() > 0) || (pixels > 0 && el.data("scrollableAreaWidth") > (el.data("scrollWrapper").innerWidth() + el.data("scrollWrapper").scrollLeft())) || o.manualContinuousScrolling) {
806
807                var scrollLength = el.data("scrollableArea").width() - el.data("scrollWrapper").width();
808                var sOffset = el.data("scrollWrapper").scrollLeft() + pixels;
809
810                if (sOffset < 0) { // Swap last element to be the first one if scroll out of the left edge of view
811
812                    var forceSwapElementLeft = function() {
813                        el.data("swappedElement", el.data("scrollableArea").children(":last").detach());
814                        el.data("scrollableArea").prepend(el.data("swappedElement"));
815                        el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + el.data("swappedElement").outerWidth(true));
816                    };
817
818                    while (sOffset < 0) { // keep swap elements left until it has enough length for scrolling left
819                        forceSwapElementLeft();
820                        sOffset = el.data("scrollableArea").children(":first").outerWidth(true) + sOffset;
821                    }
822
823                } else if (sOffset - scrollLength > 0) { // Swap the first element to be the last one if scroll out of the right edge of view
824
825                    var forceSwapElementRight = function() {
826                        el.data("swappedElement", el.data("scrollableArea").children(":first").detach());
827                        el.data("scrollableArea").append(el.data("swappedElement"));
828                        var wrapperLeft = el.data("scrollWrapper").scrollLeft();
829                        el.data("scrollWrapper").scrollLeft(wrapperLeft - el.data("swappedElement").outerWidth(true));
830                    };
831
832                    while (sOffset - scrollLength > 0) { // keep swap elements right until it has enough length for scrolling right
833                        forceSwapElementRight();
834                        sOffset = sOffset - el.data("scrollableArea").children(":last").outerWidth(true);
835                    }
836
837                }
838
839                if (o.easingAfterMouseWheelScrolling) {
840
841                    el.data("scrollWrapper").animate({
842                        scrollLeft: el.data("scrollWrapper").scrollLeft() + pixels
843                    }, {
844                        duration: o.easingAfterMouseWheelScrollingDuration,
845                        easing: o.easingAfterMouseWheelFunction,
846                        complete: function() {
847                            self._showHideHotSpots();
848                            if (o.manualContinuousScrolling) {
849                                if (pixels > 0) {
850                                    self._checkContinuousSwapRight();
851                                } else {
852                                    self._checkContinuousSwapLeft();
853                                }
854                            }
855                        }
856                    });
857
858                } else {
859                    el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + pixels);
860                    self._showHideHotSpots();
861
862                    if (o.manualContinuousScrolling) {
863                        if (pixels > 0) {
864                            self._checkContinuousSwapRight();
865                        } else {
866                            self._checkContinuousSwapLeft();
867                        }
868                    }
869                }
870
871            }
872
873        },
874        /**********************************************************
875		Adding or replacing content
876		**********************************************************/
877        /*  Arguments are:
878		content - a valid URL to a Flickr feed - string
879		manipulationMethod - addFirst, addLast or replace (default) - string
880		*/
881        getFlickrContent: function(content, manipulationMethod) {
882            var self = this,
883                el = this.element;
884
885            $.getJSON(content, function(data) {
886                // small square - size is 75x75
887                // thumbnail -> large - size is the longest side
888                var flickrImageSizes = [{
889                    size: "small square",
890                    pixels: 75,
891                    letter: "_s"
892                }, {
893                    size: "thumbnail",
894                    pixels: 100,
895                    letter: "_t"
896                }, {
897                    size: "small",
898                    pixels: 240,
899                    letter: "_m"
900                }, {
901                    size: "medium",
902                    pixels: 500,
903                    letter: ""
904                }, {
905                    size: "medium 640",
906                    pixels: 640,
907                    letter: "_z"
908                }, {
909                    size: "large",
910                    pixels: 1024,
911                    letter: "_b"
912                }];
913                var loadedFlickrImages = [];
914                var imageIdStringBuffer = [];
915                var startingIndex;
916                var numberOfFlickrItems = data.items.length;
917                var loadedFlickrImagesCounter = 0;
918
919                // Determine a plausible starting value for the
920                // image height
921                if (el.data("scrollableAreaHeight") <= 75) {
922                    startingIndex = 0;
923                } else if (el.data("scrollableAreaHeight") <= 100) {
924                    startingIndex = 1;
925                } else if (el.data("scrollableAreaHeight") <= 240) {
926                    startingIndex = 2;
927                } else if (el.data("scrollableAreaHeight") <= 500) {
928                    startingIndex = 3;
929                } else if (el.data("scrollableAreaHeight") <= 640) {
930                    startingIndex = 4;
931                } else {
932                    startingIndex = 5;
933                }
934
935                // Put all items from the feed in an array.
936                // This is necessary
937                $.each(data.items, function(index, item) {
938                    loadFlickrImage(item, startingIndex);
939                });
940
941                function loadFlickrImage(item, sizeIndex) {
942                    var path = item.media.m;
943                    var imgSrc = path.replace("_m", flickrImageSizes[sizeIndex].letter);
944                    var tempImg = $("<img />").attr("src", imgSrc);
945
946                    tempImg.load(function() {
947                        // Is it still smaller? Load next size
948                        if (this.height < el.data("scrollableAreaHeight")) {
949                            // Load a bigger image, if possible
950                            if ((sizeIndex + 1) < flickrImageSizes.length) {
951                                loadFlickrImage(item, sizeIndex + 1);
952                            } else {
953                                addImageToLoadedImages(this);
954                            }
955                        } else {
956                            addImageToLoadedImages(this);
957                        }
958
959                        // Finishing stuff to do when all images have been loaded
960                        if (loadedFlickrImagesCounter === numberOfFlickrItems) {
961                            switch (manipulationMethod) {
962                                case "addFirst":
963                                    // Add the loaded content first in the scrollable area
964                                    el.data("scrollableArea").children(":first").before(loadedFlickrImages);
965                                    break;
966                                case "addLast":
967                                    // Add the loaded content last in the scrollable area
968                                    el.data("scrollableArea").children(":last").after(loadedFlickrImages);
969                                    break;
970                                default:
971                                    // Replace the content in the scrollable area
972                                    el.data("scrollableArea").html(loadedFlickrImages);
973                                    break;
974                            }
975
976                            // Recalculate the total width of the elements inside the scrollable area
977                            self.recalculateScrollableArea();
978
979                            // Determine which hotspots to show
980                            self._showHideHotSpots();
981
982                            // Trigger callback
983                            self._trigger("addedFlickrContent", null, {
984                                "addedElementIds": imageIdStringBuffer
985                            });
986                        }
987
988                    });
989                }
990
991                // Add the loaded content first or last in the scrollable area
992                function addImageToLoadedImages(imageObj) {
993                    // Calculate the scaled width
994                    var widthScalingFactor = el.data("scrollableAreaHeight") / imageObj.height;
995                    var tempWidth = Math.round(imageObj.width * widthScalingFactor);
996                    // Set an id for the image - the filename is used as an id
997                    var tempIdArr = $(imageObj).attr("src").split("/");
998                    var lastElemIndex = (tempIdArr.length - 1);
999                    tempIdArr = tempIdArr[lastElemIndex].split(".");
1000                    $(imageObj).attr("id", tempIdArr[0]);
1001                    // Set the height of the image to the height of the scrollable area and add the width
1002                    $(imageObj).css({
1003                        "height": el.data("scrollableAreaHeight"),
1004                        "width": tempWidth
1005                    });
1006                    // Add the id of the image to the array of id's - this
1007                    // is used as a parameter when the callback is triggered
1008                    imageIdStringBuffer.push(tempIdArr[0]);
1009                    // Add the image to the array of loaded images
1010                    loadedFlickrImages.push(imageObj);
1011
1012                    // Increment counter for loaded images
1013                    loadedFlickrImagesCounter++;
1014                }
1015
1016            });
1017        },
1018        /*  Arguments are:
1019		content - a valid URL to an AJAX content source - string
1020		manipulationMethod - addFirst, addLast or replace (default) - string
1021		filterTag - a jQuery selector that matches the elements from the AJAX content
1022		source that you want, for example ".myClass" or "#thisDiv" or "div" - string
1023		*/
1024        getAjaxContent: function(content, manipulationMethod, filterTag) {
1025            var self = this,
1026                el = this.element;
1027            $.ajaxSetup({
1028                cache: false
1029            });
1030
1031            $.get(content, function(data) {
1032                var filteredContent;
1033
1034                if (filterTag !== undefined) {
1035                    if (filterTag.length > 0) {
1036                        // A bit of a hack since I can't know if the element
1037                        // that the user wants is a direct child of body (= use filter)
1038                        // or other types of elements (= use find)
1039                        filteredContent = $("<div>").html(data).find(filterTag);
1040                    } else {
1041                        filteredContent = content;
1042                    }
1043                } else {
1044                    filteredContent = data;
1045                }
1046
1047                switch (manipulationMethod) {
1048                    case "addFirst":
1049                        // Add the loaded content first in the scrollable area
1050                        el.data("scrollableArea").children(":first").before(filteredContent);
1051                        break;
1052                    case "addLast":
1053                        // Add the loaded content last in the scrollable area
1054                        el.data("scrollableArea").children(":last").after(filteredContent);
1055                        break;
1056                    default:
1057                        // Replace the content in the scrollable area
1058                        el.data("scrollableArea").html(filteredContent);
1059                        break;
1060                }
1061
1062                // Recalculate the total width of the elements inside the scrollable area
1063                self.recalculateScrollableArea();
1064
1065                // Determine which hotspots to show
1066                self._showHideHotSpots();
1067
1068                // Trigger callback
1069                self._trigger("addedAjaxContent");
1070
1071            });
1072        },
1073        getHtmlContent: function(content, manipulationMethod, filterTag) {
1074            var self = this,
1075                el = this.element;
1076
1077            // No AJAX involved at all - just add raw HTML-content
1078            /* Arguments are:
1079			content - any raw HTML that you want - string
1080			manipulationMethod - addFirst, addLast or replace (default) - string
1081			filterTag - a jQuery selector that matches the elements from the AJAX content
1082			source that you want, for example ".myClass" or "#thisDiv" or "div" - string
1083			*/
1084            var filteredContent;
1085            if (filterTag !== undefined) {
1086                if (filterTag.length > 0) {
1087                    // A bit of a hack since I can't know if the element
1088                    // that the user wants is a direct child of body (= use filter)
1089                    // or other types of elements (= use find)
1090                    filteredContent = $("<div>").html(content).find(filterTag);
1091                } else {
1092                    filteredContent = content;
1093                }
1094            } else {
1095                filteredContent = content;
1096            }
1097
1098            switch (manipulationMethod) {
1099                case "addFirst":
1100                    // Add the loaded content first in the scrollable area
1101                    el.data("scrollableArea").children(":first").before(filteredContent);
1102                    break;
1103                case "addLast":
1104                    // Add the loaded content last in the scrollable area
1105                    el.data("scrollableArea").children(":last").after(filteredContent);
1106                    break;
1107                default:
1108                    // Replace the content in the scrollable area
1109                    el.data("scrollableArea").html(filteredContent);
1110                    break;
1111            }
1112
1113            // Recalculate the total width of the elements inside the scrollable area
1114            self.recalculateScrollableArea();
1115
1116            // Determine which hotspots to show
1117            self._showHideHotSpots();
1118
1119            // Trigger callback
1120            self._trigger("addedHtmlContent");
1121
1122        },
1123        /**********************************************************
1124		Recalculate the scrollable area
1125		**********************************************************/
1126        recalculateScrollableArea: function() {
1127
1128            var tempScrollableAreaWidth = 0,
1129                foundStartAtElement = false,
1130                o = this.options,
1131                el = this.element;
1132
1133            // Add up the total width of all the items inside the scrollable area
1134            el.data("scrollableArea").children(o.countOnlyClass).each(function() {
1135                // Check to see if the current element in the loop is the one where the scrolling should start
1136                if ((o.startAtElementId.length > 0) && (($(this).attr("id")) === o.startAtElementId)) {
1137                    el.data("startingPosition", tempScrollableAreaWidth);
1138                    foundStartAtElement = true;
1139                }
1140                tempScrollableAreaWidth = tempScrollableAreaWidth + $(this).outerWidth(true);
1141
1142            });
1143
1144            // If the element with the ID specified by startAtElementId
1145            // is not found, reset it
1146            if (!(foundStartAtElement)) {
1147                el.data("startAtElementId", "");
1148            }
1149
1150            // Set the width of the scrollable area
1151            el.data("scrollableAreaWidth", tempScrollableAreaWidth);
1152            el.data("scrollableArea").width(el.data("scrollableAreaWidth"));
1153
1154            // Move to the starting position
1155            el.data("scrollWrapper").scrollLeft(el.data("startingPosition"));
1156            el.data("scrollXPos", el.data("startingPosition"));
1157        },
1158        /**********************************************************
1159		Get current scrolling left offset
1160		**********************************************************/
1161        getScrollerOffset: function() {
1162            var el = this.element;
1163
1164            // Returns the current left offset
1165            // Please remember that if the scroller is in continuous
1166            // mode, the offset is not that relevant anymore since
1167            // the plugin will swap the elements inside the scroller
1168            // around and manipulate the offset in this process.
1169            return el.data("scrollWrapper").scrollLeft();
1170        },
1171        /**********************************************************
1172		Stopping, starting and doing the auto scrolling
1173		**********************************************************/
1174        stopAutoScrolling: function() {
1175            var self = this,
1176                el = this.element;
1177
1178            if (el.data("autoScrollingInterval") !== null) {
1179                clearInterval(el.data("autoScrollingInterval"));
1180                el.data("autoScrollingInterval", null);
1181
1182                // Check to see which hotspots should be active
1183                // in the position where the scroller has stopped
1184                self._showHideHotSpots();
1185
1186                self._trigger("autoScrollingStopped");
1187            }
1188        },
1189        /**********************************************************
1190		Start Autoscrolling
1191		**********************************************************/
1192        startAutoScrolling: function() {
1193            var self = this,
1194                el = this.element,
1195                o = this.options;
1196
1197            if (el.data("enabled")) {
1198                self._showHideHotSpots();
1199
1200                // Stop any running interval
1201                clearInterval(el.data("autoScrollingInterval"));
1202                el.data("autoScrollingInterval", null);
1203
1204                // Callback
1205                self._trigger("autoScrollingStarted");
1206
1207                // Start interval
1208                el.data("autoScrollingInterval", setInterval(function() {
1209
1210                    // If the scroller is not visible or
1211                    // if the scrollable area is shorter than the scroll wrapper
1212                    // any running auto scroll interval should stop.
1213                    if (!(el.data("visible")) || (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth()))) {
1214                        // Stop any running interval
1215                        clearInterval(el.data("autoScrollingInterval"));
1216                        el.data("autoScrollingInterval", null);
1217
1218                    } else {
1219
1220                        // Store the old scrollLeft value to see if the scrolling has reached the end
1221                        el.data("previousScrollLeft", el.data("scrollWrapper").scrollLeft());
1222
1223                        switch (o.autoScrollingDirection) {
1224                            case "right":
1225
1226                                el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollingStep);
1227                                if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) {
1228                                    self._trigger("autoScrollingRightLimitReached");
1229                                    self.stopAutoScrolling();
1230                                }
1231                                break;
1232
1233                            case "left":
1234                                el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollingStep);
1235                                if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) {
1236                                    self._trigger("autoScrollingLeftLimitReached");
1237                                    self.stopAutoScrolling();
1238                                }
1239                                break;
1240
1241                            case "backAndForth":
1242                                if (el.data("pingPongDirection") === "right") {
1243                                    el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (o.autoScrollingStep));
1244                                } else {
1245                                    el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (o.autoScrollingStep));
1246                                }
1247
1248                                // If the scrollLeft hasnt't changed it means that the scrolling has reached
1249                                // the end and the direction should be switched
1250                                if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) {
1251                                    if (el.data("pingPongDirection") === "right") {
1252                                        el.data("pingPongDirection", "left");
1253                                        self._trigger("autoScrollingRightLimitReached");
1254                                    } else {
1255                                        el.data("pingPongDirection", "right");
1256                                        self._trigger("autoScrollingLeftLimitReached");
1257                                    }
1258                                }
1259                                break;
1260
1261                            case "endlessLoopRight":
1262
1263                                // Do the auto scrolling
1264                                el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollingStep);
1265
1266                                self._checkContinuousSwapRight();
1267                                break;
1268                            case "endlessLoopLeft":
1269
1270                                // Do the auto scrolling
1271                                el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollingStep);
1272
1273                                self._checkContinuousSwapLeft();
1274                                break;
1275                            default:
1276                                break;
1277
1278                        }
1279                    }
1280                }, o.autoScrollingInterval));
1281            }
1282        },
1283        /**********************************************************
1284		Check Continuos Swap Right
1285		**********************************************************/
1286        _checkContinuousSwapRight: function() {
1287            var el = this.element,
1288                o = this.options;
1289
1290            // Get the width of the first element. When it has scrolled out of view,
1291            // the element swapping should be executed. A true/false variable is used
1292            // as a flag variable so the swapAt value doesn't have to be recalculated
1293            // in each loop.
1294            if (el.data("getNextElementWidth")) {
1295
1296                if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) {
1297                    // If the user has set a certain element to start at, set swapAt
1298                    // to that element width. This happens once.
1299                    el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true));
1300                    el.data("startAtElementHasNotPassed", false);
1301                } else {
1302                    // Set swapAt to the first element in the scroller
1303                    el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true));
1304                }
1305                el.data("getNextElementWidth", false);
1306            }
1307
1308            // Check to see if the swap should be done
1309            if (el.data("swapAt") <= el.data("scrollWrapper").scrollLeft()) {
1310                el.data("swappedElement", el.data("scrollableArea").children(":first").detach());
1311                el.data("scrollableArea").append(el.data("swappedElement"));
1312                var wrapperLeft = el.data("scrollWrapper").scrollLeft();
1313                el.data("scrollWrapper").scrollLeft(wrapperLeft - el.data("swappedElement").outerWidth(true));
1314                el.data("getNextElementWidth", true);
1315            }
1316        },
1317        /**********************************************************
1318		Check Continuos Swap Left
1319		**********************************************************/
1320        _checkContinuousSwapLeft: function() {
1321            var el = this.element,
1322                o = this.options;
1323
1324            // Get the width of the first element. When it has scrolled out of view,
1325            // the element swapping should be executed. A true/false variable is used
1326            // as a flag variable so the swapAt value doesn't have to be recalculated
1327            // in each loop.
1328
1329            if (el.data("getNextElementWidth")) {
1330                if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) {
1331                    el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true));
1332                    el.data("startAtElementHasNotPassed", false);
1333                } else {
1334                    el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true));
1335                }
1336
1337                el.data("getNextElementWidth", false);
1338            }
1339
1340            // Check to see if the swap should be done
1341            if (el.data("scrollWrapper").scrollLeft() === 0) {
1342
1343                el.data("swappedElement", el.data("scrollableArea").children(":last").detach());
1344                el.data("scrollableArea").prepend(el.data("swappedElement"));
1345                el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + el.data("swappedElement").outerWidth(true));
1346                el.data("getNextElementWidth", true);
1347
1348            }
1349
1350        },
1351        restoreOriginalElements: function() {
1352            var self = this,
1353                el = this.element;
1354
1355            // Restore the original content of the scrollable area
1356            el.data("scrollableArea").html(el.data("originalElements"));
1357            self.recalculateScrollableArea();
1358            self.jumpToElement("first");
1359        },
1360        show: function() {
1361            var el = this.element;
1362            el.data("visible", true);
1363            el.show();
1364        },
1365        hide: function() {
1366            var el = this.element;
1367            el.data("visible", false);
1368            el.hide();
1369        },
1370        enable: function() {
1371            var el = this.element;
1372
1373            // Enable touch scrolling
1374            if (this.options.touchScrolling) {
1375                el.data("scrollWrapper").kinetic('attach');
1376            }
1377
1378            // Set enabled to true
1379            el.data("enabled", true);
1380        },
1381        disable: function() {
1382            var self = this,
1383                el = this.element;
1384
1385            // Clear all running intervals
1386            self.stopAutoScrolling();
1387            clearInterval(el.data("rightScrollingInterval"));
1388            clearInterval(el.data("leftScrollingInterval"));
1389            clearInterval(el.data("hideHotSpotBackgroundsInterval"));
1390
1391            // Disable touch scrolling
1392            if (this.options.touchScrolling) {
1393                el.data("scrollWrapper").kinetic('detach');
1394            }
1395
1396            // Set enabled to false
1397            el.data("enabled", false);
1398        },
1399        destroy: function() {
1400            var self = this,
1401                el = this.element;
1402
1403            // Clear all running intervals
1404            self.stopAutoScrolling();
1405            clearInterval(el.data("rightScrollingInterval"));
1406            clearInterval(el.data("leftScrollingInterval"));
1407            clearInterval(el.data("hideHotSpotBackgroundsInterval"));
1408
1409            // Remove all element specific events
1410            el.data("scrollingHotSpotRight").unbind("mouseover");
1411            el.data("scrollingHotSpotRight").unbind("mouseout");
1412            el.data("scrollingHotSpotRight").unbind("mousedown");
1413
1414            el.data("scrollingHotSpotLeft").unbind("mouseover");
1415            el.data("scrollingHotSpotLeft").unbind("mouseout");
1416            el.data("scrollingHotSpotLeft").unbind("mousedown");
1417
1418            el.unbind("mousenter");
1419            el.unbind("mouseleave");
1420
1421            // Remove all elements created by the plugin
1422            el.data("scrollingHotSpotRight").remove();
1423            el.data("scrollingHotSpotLeft").remove();
1424            el.data("scrollableArea").remove();
1425            el.data("scrollWrapper").remove();
1426
1427            // Restore the original content of the scrollable area
1428            el.html(el.data("originalElements"));
1429
1430            // Call the base destroy function
1431            $.Widget.prototype.destroy.apply(this, arguments);
1432
1433        }
1434
1435    });
1436})(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.