Revert "Export"
[framework/web/web-ui-fw.git] / libs / js / jquery-mobile-1.1.0 / experiments / scrollview / jquery.mobile.scrollview.js
1 /*
2 * jQuery Mobile Framework : scrollview plugin
3 * Copyright (c) 2010 Adobe Systems Incorporated - Kin Blas (jblas@adobe.com)
4 * Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
5 * Note: Code is in draft form and is subject to change 
6 */
7 (function($,window,document,undefined){
8
9 jQuery.widget( "mobile.scrollview", jQuery.mobile.widget, {
10         options: {
11                 fps:               60,    // Frames per second in msecs.
12                 direction:         null,  // "x", "y", or null for both.
13         
14                 scrollDuration:    2000,  // Duration of the scrolling animation in msecs.
15                 overshootDuration: 250,   // Duration of the overshoot animation in msecs.
16                 snapbackDuration:  500,   // Duration of the snapback animation in msecs.
17         
18                 moveThreshold:     10,   // User must move this many pixels in any direction to trigger a scroll.
19                 moveIntervalThreshold:     150,   // Time between mousemoves must not exceed this threshold.
20         
21                 scrollMethod:      "translate",  // "translate", "position", "scroll"
22         
23                 startEventName:    "scrollstart",
24                 updateEventName:   "scrollupdate",
25                 stopEventName:     "scrollstop",
26         
27                 eventType:         $.support.touch ? "touch" : "mouse",
28         
29                 showScrollBars:    true,
30                 
31                 pagingEnabled:     false,
32                 delayedClickSelector: "a,input,textarea,select,button,.ui-btn",
33                 delayedClickEnabled: false
34         },
35
36         _makePositioned: function($ele)
37         {
38                 if ($ele.css("position") == "static")
39                         $ele.css("position", "relative");
40         },
41
42         _create: function()
43         { 
44                 this._$clip = $(this.element).addClass("ui-scrollview-clip");
45                 var $child = this._$clip.children();
46                 if ($child.length > 1) {
47                         $child = this._$clip.wrapInner("<div></div>").children();
48                 }
49                 this._$view = $child.addClass("ui-scrollview-view");
50
51                 this._$clip.css("overflow", this.options.scrollMethod === "scroll" ? "scroll" : "hidden");
52                 this._makePositioned(this._$clip);
53
54                 this._$view.css("overflow", "hidden");
55
56                 // Turn off our faux scrollbars if we are using native scrolling
57                 // to position the view.
58
59                 this.options.showScrollBars = this.options.scrollMethod === "scroll" ? false : this.options.showScrollBars;
60
61                 // We really don't need this if we are using a translate transformation
62                 // for scrolling. We set it just in case the user wants to switch methods
63                 // on the fly.
64
65                 this._makePositioned(this._$view);
66                 this._$view.css({ left: 0, top: 0 });
67
68                 this._sx = 0;
69                 this._sy = 0;
70         
71                 var direction = this.options.direction;
72                 this._hTracker = (direction !== "y")   ? new MomentumTracker(this.options) : null;
73                 this._vTracker = (direction !== "x") ? new MomentumTracker(this.options) : null;
74         
75                 this._timerInterval = 1000/this.options.fps;
76                 this._timerID = 0;
77         
78                 var self = this;
79                 this._timerCB = function(){ self._handleMomentumScroll(); };
80         
81                 this._addBehaviors();
82         },
83
84         _startMScroll: function(speedX, speedY)
85         {
86                 this._stopMScroll();
87                 this._showScrollBars();
88
89                 var keepGoing = false;
90                 var duration = this.options.scrollDuration;
91
92                 this._$clip.trigger(this.options.startEventName);
93
94                 var ht = this._hTracker;
95                 if (ht)
96                 {
97                         var c = this._$clip.width();
98                         var v = this._$view.width();
99                         ht.start(this._sx, speedX, duration, (v > c) ? -(v - c) : 0, 0);
100                         keepGoing = !ht.done();
101                 }
102
103                 var vt = this._vTracker;
104                 if (vt)
105                 {
106                         var c = this._$clip.height();
107                         var v = this._$view.height();
108                         vt.start(this._sy, speedY, duration, (v > c) ? -(v - c) : 0, 0);
109                         keepGoing = keepGoing || !vt.done();
110                 }
111
112                 if (keepGoing)
113                         this._timerID = setTimeout(this._timerCB, this._timerInterval);
114                 else
115                         this._stopMScroll();
116         },
117
118         _stopMScroll: function()
119         {
120                 if (this._timerID)
121                 {
122                         this._$clip.trigger(this.options.stopEventName);
123                         clearTimeout(this._timerID);
124                 }
125                 this._timerID = 0;
126
127                 if (this._vTracker)
128                         this._vTracker.reset();
129
130                 if (this._hTracker)
131                         this._hTracker.reset();
132
133                 this._hideScrollBars();
134         },
135
136         _handleMomentumScroll: function()
137         {
138                 var keepGoing = false;
139                 var v = this._$view;
140
141                 var x = 0, y = 0;
142
143                 var vt = this._vTracker;
144                 if (vt)
145                 {
146                         vt.update();
147                         y = vt.getPosition();
148                         keepGoing = !vt.done();
149                 }
150
151                 var ht = this._hTracker;
152                 if (ht)
153                 {
154                         ht.update();
155                         x = ht.getPosition();
156                         keepGoing = keepGoing || !ht.done();
157                 }
158
159                 this._setScrollPosition(x, y);
160                 this._$clip.trigger(this.options.updateEventName, [ { x: x, y: y } ]);
161
162                 if (keepGoing)
163                         this._timerID = setTimeout(this._timerCB, this._timerInterval); 
164                 else
165                         this._stopMScroll();
166         },
167
168         _setScrollPosition: function(x, y)
169         {
170                 this._sx = x;
171                 this._sy = y;
172
173                 var $v = this._$view;
174
175                 var sm = this.options.scrollMethod;
176
177                 switch (sm)
178                 {
179                         case "translate":
180                                 setElementTransform($v, x + "px", y + "px");
181                                 break;
182                         case "position":
183                                 $v.css({left: x + "px", top: y + "px"});
184                                 break;
185                         case "scroll":
186                                 var c = this._$clip[0];
187                                 c.scrollLeft = -x;
188                                 c.scrollTop = -y;
189                                 break;
190                 }
191
192                 var $vsb = this._$vScrollBar;
193                 var $hsb = this._$hScrollBar;
194
195                 if ($vsb)
196                 {
197                         var $sbt = $vsb.find(".ui-scrollbar-thumb");
198                         if (sm === "translate")
199                                 setElementTransform($sbt, "0px", -y/$v.height() * $sbt.parent().height() + "px");
200                         else
201                                 $sbt.css("top", -y/$v.height()*100 + "%");
202                 }
203
204                 if ($hsb)
205                 {
206                         var $sbt = $hsb.find(".ui-scrollbar-thumb");
207                         if (sm === "translate")
208                                 setElementTransform($sbt,  -x/$v.width() * $sbt.parent().width() + "px", "0px");
209                         else
210                                 $sbt.css("left", -x/$v.width()*100 + "%");
211                 }
212         },
213
214         scrollTo: function(x, y, duration)
215         {
216                 this._stopMScroll();
217                 if (!duration)
218                         return this._setScrollPosition(x, y);
219
220                 x = -x;
221                 y = -y;
222
223                 var self = this;
224                 var start = getCurrentTime();
225                 var efunc = $.easing["easeOutQuad"];
226                 var sx = this._sx;
227                 var sy = this._sy;
228                 var dx = x - sx;
229                 var dy = y - sy;
230                 var tfunc = function(){
231                         var elapsed = getCurrentTime() - start;
232                         if (elapsed >= duration)
233                         {
234                                 self._timerID = 0;
235                                 self._setScrollPosition(x, y);
236                         }
237                         else
238                         {
239                                 var ec = efunc(elapsed/duration, elapsed, 0, 1, duration);
240                                 self._setScrollPosition(sx + (dx * ec), sy + (dy * ec));
241                                 self._timerID = setTimeout(tfunc, self._timerInterval);
242                         }
243                 };
244
245                 this._timerID = setTimeout(tfunc, this._timerInterval);
246         },
247
248         getScrollPosition: function()
249         {
250                 return { x: -this._sx, y: -this._sy };
251         },
252
253         _getScrollHierarchy: function()
254         {
255                 var svh = [];
256                 this._$clip.parents(".ui-scrollview-clip").each(function(){
257                         var d = $(this).jqmData("scrollview");
258                         if (d) svh.unshift(d);
259                 });
260                 return svh;
261         },
262
263         _getAncestorByDirection: function(dir)
264         {
265                 var svh = this._getScrollHierarchy();
266                 var n = svh.length;
267                 while (0 < n--)
268                 {
269                         var sv = svh[n];
270                         var svdir = sv.options.direction;
271
272                         if (!svdir || svdir == dir)
273                                 return sv;
274                 }
275                 return null;
276         },
277
278         _handleDragStart: function(e, ex, ey)
279         {
280                 // Stop any scrolling of elements in our parent hierarcy.
281                 $.each(this._getScrollHierarchy(),function(i,sv){ sv._stopMScroll(); });
282                 this._stopMScroll();
283
284                 var c = this._$clip;
285                 var v = this._$view;
286
287                 if (this.options.delayedClickEnabled) {
288                         this._$clickEle = $(e.target).closest(this.options.delayedClickSelector);
289                 }
290                 this._lastX = ex;
291                 this._lastY = ey;
292                 this._doSnapBackX = false;
293                 this._doSnapBackY = false;
294                 this._speedX = 0;
295                 this._speedY = 0;
296                 this._directionLock = "";
297                 this._didDrag = false;
298
299                 if (this._hTracker)
300                 {
301                         var cw = parseInt(c.css("width"), 10);
302                         var vw = parseInt(v.css("width"), 10);
303                         this._maxX = cw - vw;
304                         if (this._maxX > 0) this._maxX = 0;
305                         if (this._$hScrollBar)
306                                 this._$hScrollBar.find(".ui-scrollbar-thumb").css("width", (cw >= vw ? "100%" : Math.floor(cw/vw*100)+ "%"));
307                 }
308
309                 if (this._vTracker)
310                 {
311                         var ch = parseInt(c.css("height"), 10);
312                         var vh = parseInt(v.css("height"), 10);
313                         this._maxY = ch - vh;
314                         if (this._maxY > 0) this._maxY = 0;
315                         if (this._$vScrollBar)
316                                 this._$vScrollBar.find(".ui-scrollbar-thumb").css("height", (ch >= vh ? "100%" : Math.floor(ch/vh*100)+ "%"));
317                 }
318
319                 var svdir = this.options.direction;
320
321                 this._pageDelta = 0;
322                 this._pageSize = 0;
323                 this._pagePos = 0; 
324
325                 if (this.options.pagingEnabled && (svdir === "x" || svdir === "y"))
326                 {
327                         this._pageSize = svdir === "x" ? cw : ch;
328                         this._pagePos = svdir === "x" ? this._sx : this._sy;
329                         this._pagePos -= this._pagePos % this._pageSize;
330                 }
331                 this._lastMove = 0;
332                 this._enableTracking();
333
334                 // If we're using mouse events, we need to prevent the default
335                 // behavior to suppress accidental selection of text, etc. We
336                 // can't do this on touch devices because it will disable the
337                 // generation of "click" events.
338                 //
339                 // XXX: We should test if this has an effect on links! - kin
340
341                 if (this.options.eventType == "mouse" || this.options.delayedClickEnabled)
342                         e.preventDefault();
343                 e.stopPropagation();
344         },
345
346         _propagateDragMove: function(sv, e, ex, ey, dir)
347         {
348                 this._hideScrollBars();
349                 this._disableTracking();
350                 sv._handleDragStart(e,ex,ey);
351                 sv._directionLock = dir;
352                 sv._didDrag = this._didDrag;
353         },
354
355         _handleDragMove: function(e, ex, ey)
356         {
357                 this._lastMove = getCurrentTime();
358
359                 var v = this._$view;
360
361                 var dx = ex - this._lastX;
362                 var dy = ey - this._lastY;
363                 var svdir = this.options.direction;
364
365                 if (!this._directionLock)
366                 {
367                         var x = Math.abs(dx);
368                         var y = Math.abs(dy);
369                         var mt = this.options.moveThreshold;
370
371                         if (x < mt && y < mt) {
372                                 return false;
373                         }
374
375                         var dir = null;
376                         var r = 0;
377                         if (x < y && (x/y) < 0.5) {
378                                 dir = "y";
379                         }
380                         else if (x > y && (y/x) < 0.5) {
381                                 dir = "x";
382                         }
383
384                         if (svdir && dir && svdir != dir)
385                         {
386                                 // This scrollview can't handle the direction the user
387                                 // is attempting to scroll. Find an ancestor scrollview
388                                 // that can handle the request.
389
390                                 var sv = this._getAncestorByDirection(dir);
391                                 if (sv)
392                                 {
393                                         this._propagateDragMove(sv, e, ex, ey, dir);
394                                         return false;
395                                 }
396                         }
397
398                         this._directionLock = svdir ? svdir : (dir ? dir : "none");
399                 }
400
401                 var newX = this._sx;
402                 var newY = this._sy;
403
404                 if (this._directionLock !== "y" && this._hTracker)
405                 {
406                         var x = this._sx;
407                         this._speedX = dx;
408                         newX = x + dx;
409
410                         // Simulate resistance.
411
412                         this._doSnapBackX = false;
413                         if (newX > 0 || newX < this._maxX)
414                         {
415                                 if (this._directionLock === "x")
416                                 {
417                                         var sv = this._getAncestorByDirection("x");
418                                         if (sv)
419                                         {
420                                                 this._setScrollPosition(newX > 0 ? 0 : this._maxX, newY);
421                                                 this._propagateDragMove(sv, e, ex, ey, dir);
422                                                 return false;
423                                         }
424                                 }
425                                 newX = x + (dx/2);
426                                 this._doSnapBackX = true;
427                         }
428                 }
429
430                 if (this._directionLock !== "x" && this._vTracker)
431                 {
432                         var y = this._sy;
433                         this._speedY = dy;
434                         newY = y + dy;
435
436                         // Simulate resistance.
437
438                         this._doSnapBackY = false;
439                         if (newY > 0 || newY < this._maxY)
440                         {
441                                 if (this._directionLock === "y")
442                                 {
443                                         var sv = this._getAncestorByDirection("y");
444                                         if (sv)
445                                         {
446                                                 this._setScrollPosition(newX, newY > 0 ? 0 : this._maxY);
447                                                 this._propagateDragMove(sv, e, ex, ey, dir);
448                                                 return false;
449                                         }
450                                 }
451
452                                 newY = y + (dy/2);
453                                 this._doSnapBackY = true;
454                         }
455
456                 }
457
458                 if (this.options.pagingEnabled && (svdir === "x" || svdir === "y"))
459                 {
460                         if (this._doSnapBackX || this._doSnapBackY)
461                                 this._pageDelta = 0;
462                         else
463                         {
464                                 var opos = this._pagePos;
465                                 var cpos = svdir === "x" ? newX : newY;
466                                 var delta = svdir === "x" ? dx : dy;
467
468                                 this._pageDelta = (opos > cpos && delta < 0) ? this._pageSize : ((opos < cpos && delta > 0) ? -this._pageSize : 0);
469                         }
470                 }
471
472                 this._didDrag = true;
473                 this._lastX = ex;
474                 this._lastY = ey;
475
476                 this._setScrollPosition(newX, newY);
477
478                 this._showScrollBars();
479
480                 // Call preventDefault() to prevent touch devices from
481                 // scrolling the main window.
482
483                 // e.preventDefault();
484                 
485                 return false;
486         },
487
488         _handleDragStop: function(e)
489         {
490                 var l = this._lastMove;
491                 var t = getCurrentTime();
492                 var doScroll = l && (t - l) <= this.options.moveIntervalThreshold;
493
494                 var sx = (this._hTracker && this._speedX && doScroll) ? this._speedX : (this._doSnapBackX ? 1 : 0);
495                 var sy = (this._vTracker && this._speedY && doScroll) ? this._speedY : (this._doSnapBackY ? 1 : 0);
496
497                 var svdir = this.options.direction;
498                 if (this.options.pagingEnabled && (svdir === "x" || svdir === "y") && !this._doSnapBackX && !this._doSnapBackY)
499                 {
500                         var x = this._sx;
501                         var y = this._sy;
502                         if (svdir === "x")
503                                 x = -this._pagePos + this._pageDelta;
504                         else
505                                 y = -this._pagePos + this._pageDelta;
506
507                         this.scrollTo(x, y, this.options.snapbackDuration);
508                 }
509                 else if (sx || sy)
510                         this._startMScroll(sx, sy);
511                 else
512                         this._hideScrollBars();
513
514                 this._disableTracking();
515
516                 if (!this._didDrag && this.options.delayedClickEnabled && this._$clickEle.length) {
517                         this._$clickEle
518                                 .trigger("mousedown")
519                                 //.trigger("focus")
520                                 .trigger("mouseup")
521                                 .trigger("click");
522                 }
523
524                 // If a view scrolled, then we need to absorb
525                 // the event so that links etc, underneath our
526                 // cursor/finger don't fire.
527
528                 return this._didDrag ? false : undefined;
529         },
530
531         _enableTracking: function()
532         {
533                 $(document).bind(this._dragMoveEvt, this._dragMoveCB);
534                 $(document).bind(this._dragStopEvt, this._dragStopCB);
535         },
536
537         _disableTracking: function()
538         {
539                 $(document).unbind(this._dragMoveEvt, this._dragMoveCB);
540                 $(document).unbind(this._dragStopEvt, this._dragStopCB);
541         },
542
543         _showScrollBars: function()
544         {
545                 var vclass = "ui-scrollbar-visible";
546                 if (this._$vScrollBar) this._$vScrollBar.addClass(vclass);
547                 if (this._$hScrollBar) this._$hScrollBar.addClass(vclass);
548         },
549
550         _hideScrollBars: function()
551         {
552                 var vclass = "ui-scrollbar-visible";
553                 if (this._$vScrollBar) this._$vScrollBar.removeClass(vclass);
554                 if (this._$hScrollBar) this._$hScrollBar.removeClass(vclass);
555         },
556
557         _addBehaviors: function()
558         {
559                 var self = this;
560                 if (this.options.eventType === "mouse")
561                 {
562                         this._dragStartEvt = "mousedown";
563                         this._dragStartCB = function(e){ return self._handleDragStart(e, e.clientX, e.clientY); };
564
565                         this._dragMoveEvt = "mousemove";
566                         this._dragMoveCB = function(e){ return self._handleDragMove(e, e.clientX, e.clientY); };
567
568                         this._dragStopEvt = "mouseup";
569                         this._dragStopCB = function(e){ return self._handleDragStop(e); };
570                 }
571                 else // "touch"
572                 {
573                         this._dragStartEvt = "touchstart";
574                         this._dragStartCB = function(e)
575                         {
576                                 var t = e.originalEvent.targetTouches[0];
577                                 return self._handleDragStart(e, t.pageX, t.pageY);
578                         };
579
580                         this._dragMoveEvt = "touchmove";
581                         this._dragMoveCB = function(e)
582                         {
583                                 var t = e.originalEvent.targetTouches[0];
584                                 return self._handleDragMove(e, t.pageX, t.pageY);
585                         };
586
587                         this._dragStopEvt = "touchend";
588                         this._dragStopCB = function(e){ return self._handleDragStop(e); };
589                 }
590
591                 this._$view.bind(this._dragStartEvt, this._dragStartCB);
592
593                 if (this.options.showScrollBars)
594                 {
595                         var $c = this._$clip;
596                         var prefix = "<div class=\"ui-scrollbar ui-scrollbar-";
597                         var suffix = "\"><div class=\"ui-scrollbar-track\"><div class=\"ui-scrollbar-thumb\"></div></div></div>";
598                         if (this._vTracker)
599                         {
600                                 $c.append(prefix + "y" + suffix);
601                                 this._$vScrollBar = $c.children(".ui-scrollbar-y");
602                         }
603                         if (this._hTracker)
604                         {
605                                 $c.append(prefix + "x" + suffix);
606                                 this._$hScrollBar = $c.children(".ui-scrollbar-x");
607                         }
608                 }
609         }
610 });
611
612 function setElementTransform($ele, x, y)
613 {
614         var v = "translate3d(" + x + "," + y + ", 0px)";
615         $ele.css({
616                 "-moz-transform": v,
617                 "-webkit-transform": v,
618                 "transform": v
619         });
620 }
621
622
623 function MomentumTracker(options)
624 {
625         this.options = $.extend({}, options);
626         this.easing = "easeOutQuad";
627         this.reset();
628 }
629
630 var tstates = {
631         scrolling: 0,
632         overshot:  1,
633         snapback:  2,
634         done:      3
635 };
636
637 function getCurrentTime() { return (new Date()).getTime(); }
638
639 $.extend(MomentumTracker.prototype, {
640         start: function(pos, speed, duration, minPos, maxPos)
641         {
642                 this.state = (speed != 0) ? ((pos < minPos || pos > maxPos) ? tstates.snapback : tstates.scrolling) : tstates.done;
643                 this.pos = pos;
644                 this.speed = speed;
645                 this.duration = (this.state == tstates.snapback) ? this.options.snapbackDuration : duration;
646                 this.minPos = minPos;
647                 this.maxPos = maxPos;
648
649                 this.fromPos = (this.state == tstates.snapback) ? this.pos : 0;
650                 this.toPos = (this.state == tstates.snapback) ? ((this.pos < this.minPos) ? this.minPos : this.maxPos) : 0;
651
652                 this.startTime = getCurrentTime();
653         },
654
655         reset: function()
656         {
657                 this.state = tstates.done;
658                 this.pos = 0;
659                 this.speed = 0;
660                 this.minPos = 0;
661                 this.maxPos = 0;
662                 this.duration = 0;
663         },
664
665         update: function()
666         {
667                 var state = this.state;
668                 if (state == tstates.done)
669                         return this.pos;
670
671                 var duration = this.duration;
672                 var elapsed = getCurrentTime() - this.startTime;
673                 elapsed = elapsed > duration ? duration : elapsed;
674
675                 if (state == tstates.scrolling || state == tstates.overshot)
676                 {
677                         var dx = this.speed * (1 - $.easing[this.easing](elapsed/duration, elapsed, 0, 1, duration));
678         
679                         var x = this.pos + dx;
680         
681                         var didOverShoot = (state == tstates.scrolling) && (x < this.minPos || x > this.maxPos);
682                         if (didOverShoot)
683                                 x = (x < this.minPos) ? this.minPos : this.maxPos;
684                 
685                         this.pos = x;
686         
687                         if (state == tstates.overshot)
688                         {
689                                 if (elapsed >= duration)
690                                 {
691                                         this.state = tstates.snapback;
692                                         this.fromPos = this.pos;
693                                         this.toPos = (x < this.minPos) ? this.minPos : this.maxPos;
694                                         this.duration = this.options.snapbackDuration;
695                                         this.startTime = getCurrentTime();
696                                         elapsed = 0;
697                                 }
698                         }
699                         else if (state == tstates.scrolling)
700                         {
701                                 if (didOverShoot)
702                                 {
703                                         this.state = tstates.overshot;
704                                         this.speed = dx / 2;
705                                         this.duration = this.options.overshootDuration;
706                                         this.startTime = getCurrentTime();
707                                 }
708                                 else if (elapsed >= duration)
709                                         this.state = tstates.done;
710                         }
711                 }
712                 else if (state == tstates.snapback)
713                 {
714                         if (elapsed >= duration)
715                         {
716                                 this.pos = this.toPos;
717                                 this.state = tstates.done;              
718                         }
719                         else
720                                 this.pos = this.fromPos + ((this.toPos - this.fromPos) * $.easing[this.easing](elapsed/duration, elapsed, 0, 1, duration));
721                 }
722
723                 return this.pos;
724         },
725
726         done: function() { return this.state == tstates.done; },
727         getPosition: function(){ return this.pos; }
728 });
729
730 jQuery.widget( "mobile.scrolllistview", jQuery.mobile.scrollview, {
731         options: {
732                 direction: "y"
733         },
734
735         _create: function() {
736                 $.mobile.scrollview.prototype._create.call(this);
737         
738                 // Cache the dividers so we don't have to search for them everytime the
739                 // view is scrolled.
740                 //
741                 // XXX: Note that we need to update this cache if we ever support lists
742                 //      that can dynamically update their content.
743         
744                 this._$dividers = this._$view.find(":jqmData(role='list-divider')");
745                 this._lastDivider = null;
746         },
747
748         _setScrollPosition: function(x, y)
749         {
750                 // Let the view scroll like it normally does.
751         
752                 $.mobile.scrollview.prototype._setScrollPosition.call(this, x, y);
753
754                 y = -y;
755
756                 // Find the dividers for the list.
757
758                 var $divs = this._$dividers;
759                 var cnt = $divs.length;
760                 var d = null;
761                 var dy = 0;
762                 var nd = null;
763
764                 for (var i = 0; i < cnt; i++)
765                 {
766                         nd = $divs.get(i);
767                         var t = nd.offsetTop;
768                         if (y >= t)
769                         {
770                                 d = nd;
771                                 dy = t;
772                         }
773                         else if (d)
774                                 break;
775                 }
776
777                 // If we found a divider to move position it at the top of the
778                 // clip view.
779
780                 if (d)
781                 {
782                         var h = d.offsetHeight;
783                         var mxy = (d != nd) ? nd.offsetTop : (this._$view.get(0).offsetHeight);
784                         if (y + h >= mxy)
785                                 y = (mxy - h) - dy;
786                         else
787                                 y = y - dy;
788
789                         // XXX: Need to convert this over to using $().css() and supporting the non-transform case.
790
791                         var ld = this._lastDivider;
792                         if (ld && d != ld) {
793                                 setElementTransform($(ld), 0, 0);
794                         }
795                         setElementTransform($(d), 0, y + "px");
796                         this._lastDivider = d;
797
798                 }
799         }
800 });
801
802 })(jQuery,window,document); // End Component