smooth_rails 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1077 @@
1
+ /*
2
+ * jQuery SmoothDivScroll 1.2
3
+ *
4
+ * Copyright (c) 2012 Thomas Kahn
5
+ * Licensed under the GPL license.
6
+ *
7
+ * http://www.smoothdivscroll.com/
8
+ *
9
+ * Depends:
10
+ * jquery-1.7.x.min.js
11
+ Please use //ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js
12
+
13
+ * jquery.ui.widget.js
14
+ * jquery.ui.effects.min.js
15
+ Make your own custom download at http://jqueryui.com/download.
16
+ First deslect 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
+ Download the latest version at http://brandonaaron.net/code/mousewheel/demos
21
+ *
22
+ */
23
+ (function ($) {
24
+
25
+ $.widget("thomaskahn.smoothDivScroll", {
26
+ // Default options
27
+ options: {
28
+ // Classes for elements added by Smooth Div Scroll
29
+ scrollingHotSpotLeftClass: "scrollingHotSpotLeft", // String
30
+ scrollingHotSpotRightClass: "scrollingHotSpotRight", // String
31
+ scrollableAreaClass: "scrollableArea", // String
32
+ scrollWrapperClass: "scrollWrapper", // String
33
+
34
+ // Misc settings
35
+ hiddenOnStart: false, // Boolean
36
+ ajaxContentURL: "", // String
37
+ countOnlyClass: "", // String
38
+ startAtElementId: "", // String
39
+
40
+ // Hotspot scrolling
41
+ hotSpotScrolling: true, // Boolean
42
+ hotSpotScrollingStep: 15, // Pixels
43
+ hotSpotScrollingInterval: 10, // Milliseconds
44
+ hotSpotMouseDownSpeedBooster: 3, // Integer
45
+ visibleHotSpotBackgrounds: "onstart", // always, onstart or empty (no visible hotspots)
46
+ hotSpotsVisibleTime: 5000, // Milliseconds
47
+ easingAfterHotSpotScrolling: true, // Boolean
48
+ easingAfterHotSpotScrollingDistance: 10, // Pixels
49
+ easingAfterHotSpotScrollingDuration: 300, // Milliseconds
50
+ easingAfterHotSpotScrollingFunction: "easeOutQuart", // String
51
+
52
+ // Mousewheel scrolling
53
+ mousewheelScrolling: false, // Boolean
54
+ mousewheelScrollingStep: 70, // Pixels
55
+ easingAfterMouseWheelScrolling: true, // Boolean
56
+ easingAfterMouseWheelScrollingDuration: 300, // Milliseconds
57
+ easingAfterMouseWheelScrollingFunction: "easeOutQuart", // String
58
+
59
+ // Manual scrolling (hotspot and/or mousewheel scrolling)
60
+ manualContinuousScrolling: false, // Boolean
61
+
62
+ // Autoscrolling
63
+ autoScrollingMode: "", // String
64
+ autoScrollingDirection: "endlessloopright", // String
65
+ autoScrollingStep: 1, // Pixels
66
+ autoScrollingInterval: 10, // Milliseconds
67
+
68
+ // Easing for when the scrollToElement method is used
69
+ scrollToAnimationDuration: 1000, // Milliseconds
70
+ scrollToEasingFunction: "easeOutQuart" // String
71
+ },
72
+ _create: function () {
73
+ var self = this, o = this.options, el = this.element;
74
+
75
+ // Create additional elements needed by the plugin
76
+ // First the wrappers
77
+ el.wrapInner("<div class='" + o.scrollableAreaClass + "'>").wrapInner("<div class='" + o.scrollWrapperClass + "'>");
78
+ // Then the hot spots
79
+ el.prepend("<div class='" + o.scrollingHotSpotLeftClass + "'></div><div class='" + o.scrollingHotSpotRightClass + "'></div>");
80
+
81
+ // Create variables in the element data storage
82
+ el.data("scrollWrapper", el.find("." + o.scrollWrapperClass));
83
+ el.data("scrollingHotSpotRight", el.find("." + o.scrollingHotSpotRightClass));
84
+ el.data("scrollingHotSpotLeft", el.find("." + o.scrollingHotSpotLeftClass));
85
+ el.data("scrollableArea", el.find("." + o.scrollableAreaClass));
86
+ el.data("speedBooster", 1);
87
+ el.data("scrollXPos", 0);
88
+ el.data("hotSpotWidth", el.data("scrollingHotSpotLeft").innerWidth());
89
+ el.data("scrollableAreaWidth", 0);
90
+ el.data("startingPosition", 0);
91
+ el.data("rightScrollingInterval", null);
92
+ el.data("leftScrollingInterval", null);
93
+ el.data("autoScrollingInterval", null);
94
+ el.data("hideHotSpotBackgroundsInterval", null);
95
+ el.data("previousScrollLeft", 0);
96
+ el.data("pingPongDirection", "right");
97
+ el.data("getNextElementWidth", true);
98
+ el.data("swapAt", null);
99
+ el.data("startAtElementHasNotPassed", true);
100
+ el.data("swappedElement", null);
101
+ el.data("originalElements", el.data("scrollableArea").children(o.countOnlyClass));
102
+ el.data("visible", true);
103
+ el.data("enabled", true);
104
+ el.data("scrollableAreaHeight", el.data("scrollableArea").height());
105
+ el.data("scrollerOffset", el.offset());
106
+ el.data("initialAjaxContentLoaded", false);
107
+
108
+
109
+ /*****************************************
110
+ SET UP EVENTS FOR SCROLLING RIGHT
111
+ *****************************************/
112
+ // Check the mouse X position and calculate
113
+ // the relative X position inside the right hotspot
114
+ el.data("scrollingHotSpotRight").bind("mousemove", function (e) {
115
+ var x = e.pageX - (this.offsetLeft + el.data("scrollerOffset").left);
116
+ el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.hotSpotScrollingStep));
117
+ if (el.data("scrollXPos") === Infinity) {
118
+ el.data("scrollXPos", 0);
119
+ }
120
+ });
121
+
122
+ // Mouseover right hotspot - scrolling
123
+ el.data("scrollingHotSpotRight").bind("mouseover", function () {
124
+
125
+ // Stop any ongoing animations
126
+ el.data("scrollWrapper").stop(true, false);
127
+
128
+ // Stop any ongoing autoscrolling
129
+ self.stopAutoScrolling();
130
+
131
+ // Start the scrolling interval
132
+ el.data("rightScrollingInterval", setInterval(function () {
133
+ if (el.data("scrollXPos") > 0 && el.data("enabled")) {
134
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (el.data("scrollXPos") * el.data("speedBooster")));
135
+
136
+ if (o.manualContinuousScrolling) {
137
+ self._checkContinuousSwapRight();
138
+ }
139
+
140
+ self._showHideHotSpots();
141
+ }
142
+ }, o.hotSpotScrollingInterval));
143
+
144
+ // Callback
145
+ self._trigger("mouseOverRightHotSpot");
146
+
147
+ });
148
+
149
+ // Mouseout right hotspot - stop scrolling
150
+ el.data("scrollingHotSpotRight").bind("mouseout", function () {
151
+ clearInterval(el.data("rightScrollingInterval"));
152
+ el.data("scrollXPos", 0);
153
+
154
+ // Easing out after scrolling
155
+ if (o.easingAfterHotSpotScrolling && el.data("enabled")) {
156
+ el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollWrapper").scrollLeft() + o.easingAfterHotSpotScrollingDistance }, { duration: o.easingAfterHotSpotScrollingDuration, easing: o.easingAfterHotSpotScrollingFunction });
157
+ }
158
+ });
159
+
160
+
161
+ // mousedown right hotspot (add scrolling speed booster)
162
+ el.data("scrollingHotSpotRight").bind("mousedown", function () {
163
+ el.data("speedBooster", o.hotSpotMouseDownSpeedBooster);
164
+ });
165
+
166
+ // mouseup anywhere (stop boosting the scrolling speed)
167
+ $("body").bind("mouseup", function () {
168
+ el.data("speedBooster", 1);
169
+ });
170
+
171
+ /*****************************************
172
+ SET UP EVENTS FOR SCROLLING LEFT
173
+ *****************************************/
174
+ // Check the mouse X position and calculate
175
+ // the relative X position inside the left hotspot
176
+ el.data("scrollingHotSpotLeft").bind("mousemove", function (e) {
177
+ //var x = el.data("hotSpotWidth") - (e.pageX - el.data("scrollerOffset").left);
178
+ var x = ((this.offsetLeft + el.data("scrollerOffset").left + el.data("hotSpotWidth")) - e.pageX);
179
+ el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.hotSpotScrollingStep));
180
+
181
+ if (el.data("scrollXPos") === Infinity) {
182
+ el.data("scrollXPos", 0);
183
+ }
184
+
185
+ });
186
+
187
+ // Mouseover left hotspot
188
+ el.data("scrollingHotSpotLeft").bind("mouseover", function () {
189
+ // Stop any ongoing animations
190
+ el.data("scrollWrapper").stop(true, false);
191
+
192
+ // Stop any ongoing autoscrolling
193
+ self.stopAutoScrolling();
194
+
195
+ el.data("leftScrollingInterval", setInterval(function () {
196
+ if (el.data("scrollXPos") > 0 && el.data("enabled")) {
197
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (el.data("scrollXPos") * el.data("speedBooster")));
198
+
199
+ if (o.manualContinuousScrolling) {
200
+ self._checkContinuousSwapLeft();
201
+ }
202
+
203
+ self._showHideHotSpots();
204
+ }
205
+ }, o.hotSpotScrollingInterval));
206
+
207
+ // Callback
208
+ self._trigger("mouseOverLeftHotSpot");
209
+ });
210
+
211
+ // mouseout left hotspot
212
+ el.data("scrollingHotSpotLeft").bind("mouseout", function () {
213
+ clearInterval(el.data("leftScrollingInterval"));
214
+ el.data("scrollXPos", 0);
215
+
216
+ // Easing out after scrolling
217
+ if (o.easingAfterHotSpotScrolling && el.data("enabled")) {
218
+ el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollWrapper").scrollLeft() - o.easingAfterHotSpotScrollingDistance }, { duration: o.easingAfterHotSpotScrollingDuration, easing: o.easingAfterHotSpotScrollingFunction });
219
+ }
220
+
221
+ });
222
+
223
+ // mousedown left hotspot (add scrolling speed booster)
224
+ el.data("scrollingHotSpotLeft").bind("mousedown", function () {
225
+ el.data("speedBooster", o.hotSpotMouseDownSpeedBooster);
226
+ });
227
+
228
+ /*****************************************
229
+ SET UP EVENT FOR MOUSEWHEEL SCROLLING
230
+ *****************************************/
231
+ el.data("scrollableArea").mousewheel(function (event, delta) {
232
+ if (el.data("enabled") && o.mousewheelScrolling) {
233
+ event.preventDefault();
234
+
235
+ // Stop any ongoing autoscrolling if it's running
236
+ self.stopAutoScrolling();
237
+
238
+
239
+ // Can be either positive or negative
240
+ var pixels = Math.round(o.mousewheelScrollingStep * delta);
241
+ self.move(pixels);
242
+
243
+ }
244
+ });
245
+
246
+ // Capture and disable mousewheel events when the pointer
247
+ // is over any of the hotspots
248
+ if (o.mousewheelScrolling) {
249
+ el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).mousewheel(function (event, delta) {
250
+ event.preventDefault();
251
+ });
252
+ }
253
+
254
+ /*****************************************
255
+ SET UP EVENT FOR RESIZING THE BROWSER WINDOW
256
+ *****************************************/
257
+ $(window).bind("resize", function () {
258
+ self._showHideHotSpots();
259
+ self._trigger("windowResized");
260
+ });
261
+
262
+ /*****************************************
263
+ FETCHING AJAX CONTENT ON INITIALIZATION
264
+ *****************************************/
265
+ // If there's an ajaxContentURL in the options,
266
+ // fetch the content
267
+ if (o.ajaxContentURL.length > 0) {
268
+ self.changeContent(o.ajaxContentURL, "", "html", "replace");
269
+ }
270
+
271
+ // Should it be hidden on start?
272
+ if (o.hiddenOnStart) {
273
+ self.hide();
274
+ }
275
+
276
+ /*****************************************
277
+ AUTOSCROLLING
278
+ *****************************************/
279
+ // The $(window).load event handler is used the width of the elements are not calculated
280
+ // properly until then, at least not in Google Chrome. The start of the autoscrolling and the
281
+ // setting of the hotspot backgrounds is started here as well for the same reason.
282
+ // If the autoscrolling is not started in $(window).load, it won't start because it
283
+ // will interpret the scrollable areas as too short.
284
+ $(window).load(function () {
285
+
286
+ // If scroller is not hidden, recalculate the scrollable area
287
+ if (!(o.hiddenOnStart)) {
288
+ self.recalculateScrollableArea();
289
+ }
290
+
291
+ // Autoscrolling is active
292
+ if ((o.autoScrollingMode.length > 0) && !(o.hiddenOnStart)) {
293
+ self.startAutoScrolling();
294
+ }
295
+
296
+ // If the user wants to have visible hotspot backgrounds,
297
+ // here is where it's taken care of
298
+
299
+ if (o.autoScrollingMode !== "always") {
300
+
301
+ switch (o.visibleHotSpotBackgrounds) {
302
+ case "always":
303
+ self.showHotSpotBackgrounds();
304
+ break;
305
+ case "onstart":
306
+ self.showHotSpotBackgrounds();
307
+ el.data("hideHotSpotBackgroundsInterval", setTimeout(function () {
308
+ self.hideHotSpotBackgrounds("slow");
309
+ }, o.hotSpotsVisibleTime));
310
+ break;
311
+ default:
312
+ break;
313
+ }
314
+ }
315
+
316
+ });
317
+
318
+ },
319
+ /**********************************************************
320
+ Override _setOption and handle altered options
321
+ **********************************************************/
322
+ _setOption: function (key, value) {
323
+ var self = this, o = this.options, el = this.element;
324
+
325
+ // Update option
326
+ o[key] = value;
327
+
328
+ if (key === "hotSpotScrolling") {
329
+ // Handler if the option hotSpotScrolling is altered
330
+ if (value === true) {
331
+ self._showHideHotSpots();
332
+ } else {
333
+ el.data("scrollingHotSpotLeft").hide();
334
+ el.data("scrollingHotSpotRight").hide();
335
+ }
336
+ } else if (key === "autoScrollingStep" ||
337
+ // Make sure that certain values are integers, otherwise
338
+ // they will summon bad spirits in the plugin
339
+ key === "easingAfterHotSpotScrollingDistance" ||
340
+ key === "easingAfterHotSpotScrollingDuration" ||
341
+ key === "easingAfterMouseWheelScrollingDuration") {
342
+ o[key] = parseInt(value, 10);
343
+ } else if (key === "autoScrollingInterval") {
344
+ // Handler if the autoScrollingInterval is altered
345
+ o[key] = parseInt(value, 10);
346
+ self.startAutoScrolling();
347
+ }
348
+
349
+ },
350
+ /**********************************************************
351
+ Hotspot functions
352
+ **********************************************************/
353
+ showHotSpotBackgrounds: function (fadeSpeed) {
354
+
355
+ // Alter the CSS (SmoothDivScroll.css) if you want to customize
356
+ // the look'n'feel of the visible hotspots
357
+ var self = this, el = this.element;
358
+
359
+ // Fade in the hotspot backgrounds
360
+ if (fadeSpeed !== undefined) {
361
+ // Before the fade-in starts, we need to make sure the opacity is zero
362
+ el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).css("opacity", "0.0");
363
+
364
+ el.data("scrollingHotSpotLeft").addClass("scrollingHotSpotLeftVisible");
365
+ el.data("scrollingHotSpotRight").addClass("scrollingHotSpotRightVisible");
366
+
367
+ // Fade in the hotspots
368
+ el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).fadeTo(fadeSpeed, 0.35);
369
+ }
370
+ // Don't fade, just show them
371
+ else {
372
+
373
+ // The left hotspot
374
+ el.data("scrollingHotSpotLeft").addClass("scrollingHotSpotLeftVisible");
375
+ el.data("scrollingHotSpotLeft").removeAttr("style");
376
+
377
+ // The right hotspot
378
+ el.data("scrollingHotSpotRight").addClass("scrollingHotSpotRightVisible");
379
+ el.data("scrollingHotSpotRight").removeAttr("style");
380
+ }
381
+
382
+ self._showHideHotSpots();
383
+ },
384
+ hideHotSpotBackgrounds: function (fadeSpeed) {
385
+ var el = this.element;
386
+
387
+ // Fade out the hotspot backgrounds
388
+ if (fadeSpeed !== undefined) {
389
+ // Fade out the left hotspot
390
+ el.data("scrollingHotSpotLeft").fadeTo(fadeSpeed, 0.0, function () {
391
+ el.data("scrollingHotSpotLeft").removeClass("scrollingHotSpotLeftVisible");
392
+ });
393
+
394
+ // Fade out the right hotspot
395
+ el.data("scrollingHotSpotRight").fadeTo(fadeSpeed, 0.0, function () {
396
+ el.data("scrollingHotSpotRight").removeClass("scrollingHotSpotRightVisible");
397
+ });
398
+ }
399
+ // Don't fade, just hide them
400
+ else {
401
+ el.data("scrollingHotSpotLeft").removeClass("scrollingHotSpotLeftVisible").removeAttr("style");
402
+ el.data("scrollingHotSpotRight").removeClass("scrollingHotSpotRightVisible").removeAttr("style");
403
+ }
404
+
405
+ },
406
+ // Function for showing and hiding hotspots depending on the
407
+ // offset of the scrolling
408
+ _showHideHotSpots: function () {
409
+ var self = this, el = this.element, o = this.options;
410
+
411
+ // If the manual scrolling is set
412
+ if (o.manualContinuousScrolling && o.hotSpotScrolling) {
413
+ el.data("scrollingHotSpotLeft").show();
414
+ el.data("scrollingHotSpotRight").show();
415
+ }
416
+ // Autoscrolling not set to always and hotspot scrolling enabled
417
+ else if (o.autoScrollingMode !== "always" && o.hotSpotScrolling) {
418
+ // If the scrollable area is shorter than the scroll wrapper, both hotspots
419
+ // should be hidden
420
+ if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth())) {
421
+ el.data("scrollingHotSpotLeft").hide();
422
+ el.data("scrollingHotSpotRight").hide();
423
+ }
424
+ // When you can't scroll further left the left scroll hotspot should be hidden
425
+ // and the right hotspot visible.
426
+ else if (el.data("scrollWrapper").scrollLeft() === 0) {
427
+ el.data("scrollingHotSpotLeft").hide();
428
+ el.data("scrollingHotSpotRight").show();
429
+ // Callback
430
+ self._trigger("scrollerLeftLimitReached");
431
+ // Clear interval
432
+ clearInterval(el.data("leftScrollingInterval"));
433
+ el.data("leftScrollingInterval", null);
434
+ }
435
+ // When you can't scroll further right
436
+ // the right scroll hotspot should be hidden
437
+ // and the left hotspot visible
438
+ else if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth() + el.data("scrollWrapper").scrollLeft())) {
439
+ el.data("scrollingHotSpotLeft").show();
440
+ el.data("scrollingHotSpotRight").hide();
441
+ // Callback
442
+ self._trigger("scrollerRightLimitReached");
443
+ // Clear interval
444
+ clearInterval(el.data("rightScrollingInterval"));
445
+ el.data("rightScrollingInterval", null);
446
+ }
447
+ // If you are somewhere in the middle of your
448
+ // scrolling, both hotspots should be visible
449
+ else {
450
+ el.data("scrollingHotSpotLeft").show();
451
+ el.data("scrollingHotSpotRight").show();
452
+ }
453
+ }
454
+ // If autoscrolling is set to always, there should be no hotspots
455
+ else {
456
+ el.data("scrollingHotSpotLeft").hide();
457
+ el.data("scrollingHotSpotRight").hide();
458
+ }
459
+ },
460
+ // Function for calculating the scroll position of a certain element
461
+ _setElementScrollPosition: function (method, element) {
462
+ var self = this, el = this.element, o = this.options, tempScrollPosition = 0;
463
+
464
+ switch (method) {
465
+ case "first":
466
+ el.data("scrollXPos", 0);
467
+ return true;
468
+ case "start":
469
+ // Check to see if there is a specified start element in the options
470
+ // and that the element exists in the DOM
471
+ if (o.startAtElementId !== "") {
472
+ if (el.data("scrollableArea").has("#" + o.startAtElementId)) {
473
+ tempScrollPosition = $("#" + o.startAtElementId).position().left;
474
+ el.data("scrollXPos", tempScrollPosition);
475
+ return true;
476
+ }
477
+ }
478
+ return false;
479
+ case "last":
480
+ el.data("scrollXPos", (el.data("scrollableAreaWidth") - el.data("scrollWrapper").innerWidth()));
481
+ return true;
482
+ case "number":
483
+ // Check to see that an element number is passed
484
+ if (!(isNaN(element))) {
485
+ tempScrollPosition = el.data("scrollableArea").children(o.countOnlyClass).eq(element - 1).position().left;
486
+ el.data("scrollXPos", tempScrollPosition);
487
+ return true;
488
+ }
489
+ return false;
490
+ case "id":
491
+ // Check that an element id is passed and that the element exists in the DOM
492
+ if (element.length > 0) {
493
+ if (el.data("scrollableArea").has("#" + element)) {
494
+ tempScrollPosition = $("#" + element).position().left;
495
+ el.data("scrollXPos", tempScrollPosition);
496
+ return true;
497
+ }
498
+ }
499
+ return false;
500
+ default:
501
+ return false;
502
+ }
503
+
504
+
505
+ },
506
+ /**********************************************************
507
+ Jumping to a certain element
508
+ **********************************************************/
509
+ jumpToElement: function (jumpTo, element) {
510
+ var self = this, el = this.element;
511
+
512
+ // Check to see that the scroller is enabled
513
+ if (el.data("enabled")) {
514
+ // Get the position of the element to scroll to
515
+ if (self._setElementScrollPosition(jumpTo, element)) {
516
+ // Jump to the element
517
+ el.data("scrollWrapper").scrollLeft(el.data("scrollXPos"));
518
+ // Check the hotspots
519
+ self._showHideHotSpots();
520
+ // Trigger the right callback
521
+ switch (jumpTo) {
522
+ case "first":
523
+ self._trigger("jumpedToFirstElement");
524
+ break;
525
+ case "start":
526
+ self._trigger("jumpedToStartElement");
527
+ break;
528
+ case "last":
529
+ self._trigger("jumpedToLastElement");
530
+ break;
531
+ case "number":
532
+ self._trigger("jumpedToElementNumber", null, { "elementNumber": element });
533
+ break;
534
+ case "id":
535
+ self._trigger("jumpedToElementId", null, { "elementId": element });
536
+ break;
537
+ default:
538
+ break;
539
+ }
540
+
541
+ }
542
+ }
543
+ },
544
+ /**********************************************************
545
+ Scrolling to a certain element
546
+ **********************************************************/
547
+ scrollToElement: function (scrollTo, element) {
548
+ var self = this, el = this.element, o = this.options, autoscrollingWasRunning = false;
549
+
550
+ if (el.data("enabled")) {
551
+ // Get the position of the element to scroll to
552
+ if (self._setElementScrollPosition(scrollTo, element)) {
553
+ // Stop any ongoing autoscrolling
554
+ if (el.data("autoScrollingInterval") !== null) {
555
+ self.stopAutoScrolling();
556
+ autoscrollingWasRunning = true;
557
+ }
558
+
559
+ // Stop any other running animations
560
+ // (clear queue but don't jump to the end)
561
+ el.data("scrollWrapper").stop(true, false);
562
+
563
+ // Do the scolling animation
564
+ el.data("scrollWrapper").animate({
565
+ scrollLeft: el.data("scrollXPos")
566
+ }, { duration: o.scrollToAnimationDuration, easing: o.scrollToEasingFunction, complete: function () {
567
+ // If autoscrolling was running before, start it again
568
+ if (autoscrollingWasRunning) {
569
+ self.startAutoScrolling();
570
+ }
571
+
572
+ self._showHideHotSpots();
573
+
574
+ // Trigger the right callback
575
+ switch (scrollTo) {
576
+ case "first":
577
+ self._trigger("scrolledToFirstElement");
578
+ break;
579
+ case "start":
580
+ self._trigger("scrolledToStartElement");
581
+ break;
582
+ case "last":
583
+ self._trigger("scrolledToLastElement");
584
+ break;
585
+ case "number":
586
+ self._trigger("scrolledToElementNumber", null, { "elementNumber": element });
587
+ break;
588
+ case "id":
589
+ self._trigger("scrolledToElementId", null, { "elementId": element });
590
+ break;
591
+ default:
592
+ break;
593
+ }
594
+ }
595
+ });
596
+ }
597
+ }
598
+
599
+ },
600
+ move: function (pixels) {
601
+ var self = this, el = this.element, o = this.options;
602
+ // clear queue, move to end
603
+ el.data("scrollWrapper").stop(true, true);
604
+
605
+ // Only run this code if it's possible to scroll left or right,
606
+ if ((pixels < 0 && el.data("scrollWrapper").scrollLeft() > 0) || (pixels > 0 && el.data("scrollableAreaWidth") > (el.data("scrollWrapper").innerWidth() + el.data("scrollWrapper").scrollLeft()))) {
607
+ if (o.easingAfterMouseWheelScrolling) {
608
+ el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollWrapper").scrollLeft() + pixels }, { duration: o.easingAfterMouseWheelScrollingDuration, easing: o.easingAfterMouseWheelFunction, complete: function () {
609
+ self._showHideHotSpots();
610
+ if (o.manualContinuousScrolling) {
611
+ if (pixels > 0) {
612
+ self._checkContinuousSwapRight();
613
+ } else {
614
+ self._checkContinuousSwapLeft();
615
+ }
616
+ }
617
+ }
618
+ });
619
+ } else {
620
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + pixels);
621
+ self._showHideHotSpots();
622
+
623
+ if (o.manualContinuousScrolling) {
624
+ if (pixels > 0) {
625
+ self._checkContinuousSwapRight();
626
+ } else {
627
+ self._checkContinuousSwapLeft();
628
+ }
629
+ }
630
+ }
631
+ }
632
+
633
+
634
+ },
635
+ /**********************************************************
636
+ Adding or replacing content
637
+ **********************************************************/
638
+
639
+ changeContent: function (ajaxContentURL, contentType, manipulationMethod, addWhere) {
640
+ var self = this, el = this.element;
641
+
642
+ switch (contentType) {
643
+ case "flickrFeed":
644
+ $.getJSON(ajaxContentURL, function (data) {
645
+ // small square - size is 75x75
646
+ // thumbnail -> large - size is the longest side
647
+ var flickrImageSizes = [{ size: "small square", pixels: 75, letter: "_s" },
648
+ { size: "thumbnail", pixels: 100, letter: "_t" },
649
+ { size: "small", pixels: 240, letter: "_m" },
650
+ { size: "medium", pixels: 500, letter: "" },
651
+ { size: "medium 640", pixels: 640, letter: "_z" },
652
+ { size: "large", pixels: 1024, letter: "_b"}];
653
+ var loadedFlickrImages = [];
654
+ var imageIdStringBuffer = [];
655
+ var tempIdArr = [];
656
+ var startingIndex;
657
+ var numberOfFlickrItems = data.items.length;
658
+ var loadedFlickrImagesCounter = 0;
659
+
660
+ // Determine a plausible starting value for the
661
+ // image height
662
+ if (el.data("scrollableAreaHeight") <= 75) {
663
+ startingIndex = 0;
664
+ } else if (el.data("scrollableAreaHeight") <= 100) {
665
+ startingIndex = 1;
666
+ } else if (el.data("scrollableAreaHeight") <= 240) {
667
+ startingIndex = 2;
668
+ } else if (el.data("scrollableAreaHeight") <= 500) {
669
+ startingIndex = 3;
670
+ } else if (el.data("scrollableAreaHeight") <= 640) {
671
+ startingIndex = 4;
672
+ } else {
673
+ startingIndex = 5;
674
+ }
675
+
676
+ // Put all items from the feed in an array.
677
+ // This is necessary
678
+ $.each(data.items, function (index, item) {
679
+ loadFlickrImage(item, startingIndex);
680
+ });
681
+
682
+ function loadFlickrImage(item, sizeIndex) {
683
+ var path = item.media.m;
684
+ var imgSrc = path.replace("_m", flickrImageSizes[sizeIndex].letter);
685
+ var tempImg = $("<img />").attr("src", imgSrc);
686
+
687
+ tempImg.load(function () {
688
+ // Is it still smaller? Load next size
689
+ if (this.height < el.data("scrollableAreaHeight")) {
690
+ // Load a bigger image, if possible
691
+ if ((sizeIndex + 1) < flickrImageSizes.length) {
692
+ loadFlickrImage(item, sizeIndex + 1);
693
+ } else {
694
+ addImageToLoadedImages(this);
695
+ }
696
+ }
697
+ else {
698
+ addImageToLoadedImages(this);
699
+ }
700
+
701
+ // Finishing stuff to do when all images have been loaded
702
+ if (loadedFlickrImagesCounter === numberOfFlickrItems) {
703
+
704
+
705
+ switch (manipulationMethod) {
706
+ case "add":
707
+ // Add the images to the scrollable area
708
+ if (addWhere === "first") {
709
+ el.data("scrollableArea").children(":first").before(loadedFlickrImages);
710
+ }
711
+ else {
712
+ el.data("scrollableArea").children(":last").after(loadedFlickrImages);
713
+ }
714
+ break;
715
+ default:
716
+ // Replace the content in the scrollable area
717
+ el.data("scrollableArea").html(loadedFlickrImages);
718
+ break;
719
+ }
720
+
721
+
722
+ // Recalculate the total width of the elements inside the scrollable area
723
+ // if it's not the initial AJAX content load. If so, it's taken care of
724
+ // in the $(window).load eventhandler
725
+ if (el.data("initialAjaxContentLoaded")) {
726
+ self.recalculateScrollableArea();
727
+ } else {
728
+ el.data("initialAjaxContentLoaded", true);
729
+ }
730
+
731
+ // Determine which hotspots to show
732
+ self._showHideHotSpots();
733
+
734
+ // Trigger callback
735
+ self._trigger("addedFlickrContent", null, { "addedElementIds": imageIdStringBuffer });
736
+ }
737
+
738
+ });
739
+
740
+ }
741
+
742
+ // Add the loaded content first or last in the scrollable area
743
+ function addImageToLoadedImages(imageObj) {
744
+ // Calculate the scaled width
745
+ var widthScalingFactor = el.data("scrollableAreaHeight") / imageObj.height;
746
+ var tempWidth = Math.round(imageObj.width * widthScalingFactor);
747
+ // Set an id for the image - the filename is used as an id
748
+ var tempIdArr = $(imageObj).attr("src").split("/");
749
+ var lastElemIndex = (tempIdArr.length - 1);
750
+ tempIdArr = tempIdArr[lastElemIndex].split(".");
751
+ $(imageObj).attr("id", tempIdArr[0]);
752
+ // Set the height of the image to the height of the scrollable area and add the width
753
+ $(imageObj).css({ "height": el.data("scrollableAreaHeight"), "width": tempWidth });
754
+ // Add the id of the image to the array of id's - this
755
+ // is used as a parameter when the callback is triggered
756
+ imageIdStringBuffer.push(tempIdArr[0]);
757
+ // Add the image to the array of loaded images
758
+ loadedFlickrImages.push(imageObj);
759
+
760
+ // Increment counter for loaded images
761
+ loadedFlickrImagesCounter++;
762
+ }
763
+
764
+ });
765
+ break;
766
+ default: // just add plain HTML or whatever is at the URL
767
+ $.get(ajaxContentURL, function (data) {
768
+
769
+ switch (manipulationMethod) {
770
+ case "add":
771
+ // Add the loaded content first or last in the scrollable area
772
+ if (addWhere === "first") {
773
+ el.data("scrollableArea").children(":first").before(data);
774
+ }
775
+ else {
776
+ el.data("scrollableArea").children(":last").after(data);
777
+ }
778
+ break;
779
+ default:
780
+ // Replace the content in the scrollable area
781
+ el.data("scrollableArea").html(data);
782
+ break;
783
+ }
784
+
785
+ // Recalculate the total width of the elements inside the scrollable area
786
+ // if it's not the initial AJAX content load. If so, it's taken care of
787
+ // in the $(window).load eventhandler
788
+ if (el.data("initialAjaxContentLoaded")) {
789
+ self.recalculateScrollableArea();
790
+ } else {
791
+ el.data("initialAjaxContentLoaded", true);
792
+ }
793
+
794
+ // Determine which hotspots to show
795
+ self._showHideHotSpots();
796
+
797
+ // Trigger callback
798
+ self._trigger("addedHtmlContent");
799
+
800
+ });
801
+ }
802
+ },
803
+ /**********************************************************
804
+ Recalculate the scrollable area
805
+ **********************************************************/
806
+ recalculateScrollableArea: function () {
807
+
808
+ var tempScrollableAreaWidth = 0, foundStartAtElement = false, o = this.options, el = this.element, self = this;
809
+
810
+ // Add up the total width of all the items inside the scrollable area
811
+
812
+ el.data("scrollableArea").children(o.countOnlyClass).each(function () {
813
+ // Check to see if the current element in the loop is the one where the scrolling should start
814
+ if ((o.startAtElementId.length > 0) && (($(this).attr("id")) === o.startAtElementId)) {
815
+ el.data("startingPosition", tempScrollableAreaWidth);
816
+ foundStartAtElement = true;
817
+ }
818
+ tempScrollableAreaWidth = tempScrollableAreaWidth + $(this).outerWidth(true);
819
+
820
+ });
821
+
822
+ // If the element with the ID specified by startAtElementId
823
+ // is not found, reset it
824
+ if (!(foundStartAtElement)) {
825
+ el.data("startAtElementId", "");
826
+ }
827
+
828
+ // Set the width of the scrollable area
829
+ el.data("scrollableAreaWidth", tempScrollableAreaWidth);
830
+ el.data("scrollableArea").width(el.data("scrollableAreaWidth"));
831
+
832
+ // Move to the starting position
833
+ el.data("scrollWrapper").scrollLeft(el.data("startingPosition"));
834
+ el.data("scrollXPos", el.data("startingPosition"));
835
+ },
836
+ /**********************************************************
837
+ Stopping, starting and doing the autoscrolling
838
+ **********************************************************/
839
+ stopAutoScrolling: function () {
840
+ var self = this, el = this.element;
841
+
842
+ if (el.data("autoScrollingInterval") !== null) {
843
+ clearInterval(el.data("autoScrollingInterval"));
844
+ el.data("autoScrollingInterval", null);
845
+
846
+ // Check to see which hotspots should be active
847
+ // in the position where the scroller has stopped
848
+ self._showHideHotSpots();
849
+
850
+ self._trigger("autoScrollingStopped");
851
+ }
852
+ },
853
+ startAutoScrolling: function () {
854
+ var self = this, el = this.element, o = this.options;
855
+
856
+ if (el.data("enabled")) {
857
+ self._showHideHotSpots();
858
+
859
+ // Stop any running interval
860
+ clearInterval(el.data("autoScrollingInterval"));
861
+ el.data("autoScrollingInterval", null);
862
+
863
+ // Callback
864
+ self._trigger("autoScrollingStarted");
865
+
866
+ // Start interval
867
+ el.data("autoScrollingInterval", setInterval(function () {
868
+
869
+ // If the scroller is not visible or
870
+ // if the scrollable area is shorter than the scroll wrapper
871
+ // any running autoscroll interval should stop.
872
+ if (!(el.data("visible")) || (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth()))) {
873
+ // Stop any running interval
874
+ clearInterval(el.data("autoScrollingInterval"));
875
+ el.data("autoScrollingInterval", null);
876
+ }
877
+ else {
878
+ // Store the old scrollLeft value to see if the scrolling has reached the end
879
+ el.data("previousScrollLeft", el.data("scrollWrapper").scrollLeft());
880
+
881
+ switch (o.autoScrollingDirection) {
882
+ case "right":
883
+
884
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollingStep);
885
+ if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) {
886
+ self._trigger("autoScrollingRightLimitReached");
887
+ clearInterval(el.data("autoScrollingInterval"));
888
+ el.data("autoScrollingInterval", null);
889
+ self._trigger("autoScrollingIntervalStopped");
890
+ }
891
+ break;
892
+
893
+ case "left":
894
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollingStep);
895
+ if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) {
896
+ self._trigger("autoScrollingLeftLimitReached");
897
+ clearInterval(el.data("autoScrollingInterval"));
898
+ el.data("autoScrollingInterval", null);
899
+ self._trigger("autoScrollingIntervalStopped");
900
+ }
901
+ break;
902
+
903
+ case "backandforth":
904
+ if (el.data("pingPongDirection") === "right") {
905
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (o.autoScrollingStep));
906
+ }
907
+ else {
908
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (o.autoScrollingStep));
909
+ }
910
+
911
+ // If the scrollLeft hasnt't changed it means that the scrolling has reached
912
+ // the end and the direction should be switched
913
+ if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) {
914
+ if (el.data("pingPongDirection") === "right") {
915
+ el.data("pingPongDirection", "left");
916
+ self._trigger("autoScrollingRightLimitReached");
917
+ }
918
+ else {
919
+ el.data("pingPongDirection", "right");
920
+ self._trigger("autoScrollingLeftLimitReached");
921
+ }
922
+ }
923
+ break;
924
+
925
+ case "endlessloopright":
926
+ // Do the autoscrolling
927
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollingStep);
928
+
929
+ self._checkContinuousSwapRight();
930
+ break;
931
+ case "endlessloopleft":
932
+ // Do the autoscrolling
933
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollingStep);
934
+
935
+ self._checkContinuousSwapLeft();
936
+ break;
937
+ default:
938
+ break;
939
+
940
+ }
941
+ }
942
+ }, o.autoScrollingInterval));
943
+ }
944
+ },
945
+ _checkContinuousSwapRight: function () {
946
+ var self = this, el = this.element, o = this.options;
947
+
948
+ // Get the width of the first element. When it has scrolled out of view,
949
+ // the element swapping should be executed. A true/false variable is used
950
+ // as a flag variable so the swapAt value doesn't have to be recalculated
951
+ // in each loop.
952
+ if (el.data("getNextElementWidth")) {
953
+
954
+ if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) {
955
+ // If the user has set a certain element to start at, set swapAt
956
+ // to that element width. This happens once.
957
+ el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true));
958
+ el.data("startAtElementHasNotPassed", false);
959
+ }
960
+ else {
961
+ // Set swapAt to the first element in the scroller
962
+ el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true));
963
+ }
964
+ el.data("getNextElementWidth", false);
965
+ }
966
+
967
+
968
+ // Check to see if the swap should be done
969
+ if (el.data("swapAt") <= el.data("scrollWrapper").scrollLeft()) {
970
+ el.data("swappedElement", el.data("scrollableArea").children(":first").detach());
971
+ el.data("scrollableArea").append(el.data("swappedElement"));
972
+ var wrapperLeft = el.data("scrollWrapper").scrollLeft();
973
+ el.data("scrollWrapper").scrollLeft(wrapperLeft - el.data("swappedElement").outerWidth(true));
974
+ el.data("getNextElementWidth", true);
975
+
976
+ }
977
+ },
978
+ _checkContinuousSwapLeft: function () {
979
+ var self = this, el = this.element, o = this.options;
980
+
981
+ // Get the width of the first element. When it has scrolled out of view,
982
+ // the element swapping should be executed. A true/false variable is used
983
+ // as a flag variable so the swapAt value doesn't have to be recalculated
984
+ // in each loop.
985
+
986
+ if (el.data("getNextElementWidth")) {
987
+ if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) {
988
+ el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true));
989
+ el.data("startAtElementHasNotPassed", false);
990
+ }
991
+ else {
992
+ el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true));
993
+ }
994
+
995
+ el.data("getNextElementWidth", false);
996
+ }
997
+
998
+ // Check to see if the swap should be done
999
+ if (el.data("scrollWrapper").scrollLeft() === 0) {
1000
+ el.data("swappedElement", el.data("scrollableArea").children(":last").detach());
1001
+ el.data("scrollableArea").prepend(el.data("swappedElement"));
1002
+ el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + el.data("swappedElement").outerWidth(true));
1003
+ el.data("getNextElementWidth", true);
1004
+ }
1005
+
1006
+ },
1007
+ restoreOriginalElements: function () {
1008
+ var self = this, el = this.element;
1009
+
1010
+ // Restore the original content of the scrollable area
1011
+ el.data("scrollableArea").html(el.data("originalElements"));
1012
+ self.recalculateScrollableArea();
1013
+ self.jumpToElement("first");
1014
+ },
1015
+ show: function () {
1016
+ var el = this.element;
1017
+ el.data("visible", true);
1018
+ el.show();
1019
+ },
1020
+ hide: function () {
1021
+ var el = this.element;
1022
+ el.data("visible", false);
1023
+ el.hide();
1024
+ },
1025
+ enable: function () {
1026
+ var el = this.element;
1027
+
1028
+ // Set enabled to true
1029
+ el.data("enabled", true);
1030
+ },
1031
+ disable: function () {
1032
+ var self = this, el = this.element;
1033
+
1034
+ // Clear all running intervals
1035
+ self.stopAutoScrolling();
1036
+ clearInterval(el.data("rightScrollingInterval"));
1037
+ clearInterval(el.data("leftScrollingInterval"));
1038
+ clearInterval(el.data("hideHotSpotBackgroundsInterval"));
1039
+
1040
+ // Set enabled to false
1041
+ el.data("enabled", false);
1042
+ },
1043
+ destroy: function () {
1044
+ var self = this, el = this.element;
1045
+
1046
+ // Clear all running intervals
1047
+ self.stopAutoScrolling();
1048
+ clearInterval(el.data("rightScrollingInterval"));
1049
+ clearInterval(el.data("leftScrollingInterval"));
1050
+ clearInterval(el.data("hideHotSpotBackgroundsInterval"));
1051
+
1052
+ // Remove all element specific events
1053
+ el.data("scrollingHotSpotRight").unbind("mouseover");
1054
+ el.data("scrollingHotSpotRight").unbind("mouseout");
1055
+ el.data("scrollingHotSpotRight").unbind("mousedown");
1056
+
1057
+ el.data("scrollingHotSpotLeft").unbind("mouseover");
1058
+ el.data("scrollingHotSpotLeft").unbind("mouseout");
1059
+ el.data("scrollingHotSpotLeft").unbind("mousedown");
1060
+
1061
+ // Remove all elements created by the plugin
1062
+ el.data("scrollingHotSpotRight").remove();
1063
+ el.data("scrollingHotSpotLeft").remove();
1064
+ el.data("scrollableArea").remove();
1065
+ el.data("scrollWrapper").remove();
1066
+
1067
+ // Restore the original content of the scrollable area
1068
+ el.html(el.data("originalElements"));
1069
+
1070
+ // Call the base destroy function
1071
+ $.Widget.prototype.destroy.apply(this, arguments);
1072
+
1073
+ }
1074
+
1075
+
1076
+ });
1077
+ })(jQuery);