smooth_rails 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);