mirror of
https://github.com/Hopiu/jquery-mobile.git
synced 2026-03-16 22:10:25 +00:00
Fixed a typo/bug in scrollview.js that was causing the paging bool to be set improperly. Turned on scrollview paging in scrollview-direction.html. Items still left to do: - Code refactoring/cleanup. - Modify the code so that scroll offsets are stored as positive values. This will make it easier for folks to understand.
780 lines
18 KiB
JavaScript
780 lines
18 KiB
JavaScript
/*
|
|
* jQuery Mobile Framework : scrollview plugin
|
|
* Copyright (c) 2010 Adobe Systems Incorporated - Kin Blas (jblas@adobe.com)
|
|
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
|
|
* Note: Code is in draft form and is subject to change
|
|
*/
|
|
(function($,window,document,undefined){
|
|
|
|
jQuery.widget( "mobile.scrollview", jQuery.mobile.widget, {
|
|
options: {
|
|
fps: 60, // Frames per second in msecs.
|
|
direction: null, // "x", "y", or null for both.
|
|
|
|
scrollDuration: 2000, // Duration of the scrolling animation in msecs.
|
|
overshootDuration: 250, // Duration of the overshoot animation in msecs.
|
|
snapbackDuration: 500, // Duration of the snapback animation in msecs.
|
|
|
|
moveThreshold: 10, // User must move this many pixels in any direction to trigger a scroll.
|
|
moveIntervalThreshold: 100, // Time between mousemoves must not exceed this threshold.
|
|
|
|
useCSSTransform: true, // Use CSS "transform" property instead of "top" and "left" for positioning.
|
|
|
|
startEventName: "scrollstart",
|
|
updateEventName: "scrollupdate",
|
|
stopEventName: "scrollstop",
|
|
|
|
eventType: $.support.touch ? "touch" : "mouse",
|
|
|
|
showScrollBars: true,
|
|
|
|
pagingEnabled: false
|
|
},
|
|
|
|
_makePositioned: function($ele)
|
|
{
|
|
if ($ele.css("position") == "static")
|
|
$ele.css("position", "relative");
|
|
},
|
|
|
|
_create: function()
|
|
{
|
|
this._$clip = $(this.element).addClass("ui-scrollview-clip");
|
|
var $child = this._$clip.children();
|
|
if ($child.length > 1) {
|
|
$child = this._$clip.wrapInner("<div></div>").children();
|
|
}
|
|
this._$view = $child.addClass("ui-scrollview-view");
|
|
|
|
this._$clip.css("overflow", "hidden");
|
|
this._makePositioned(this._$clip);
|
|
|
|
this._$view.css("overflow", "hidden");
|
|
|
|
if (!this.options.useCSSTransform)
|
|
{
|
|
this._makePositioned(this._$view);
|
|
this._$view.css({ left: 0, top: 0 });
|
|
}
|
|
|
|
this._sx = 0;
|
|
this._sy = 0;
|
|
|
|
var direction = this.options.direction;
|
|
this._hTracker = (direction != "y") ? new MomentumTracker(this.options) : null;
|
|
this._vTracker = (direction != "x") ? new MomentumTracker(this.options) : null;
|
|
|
|
this._timerInterval = 1000/this.options.fps;
|
|
this._timerID = 0;
|
|
|
|
var self = this;
|
|
this._timerCB = function(){ self._handleMomentumScroll(); };
|
|
|
|
this._addBehaviors();
|
|
},
|
|
|
|
_startMScroll: function(speedX, speedY)
|
|
{
|
|
this._stopMScroll();
|
|
this._showScrollBars();
|
|
|
|
var keepGoing = false;
|
|
var duration = this.options.scrollDuration;
|
|
|
|
this._$clip.trigger(this.options.startEventName);
|
|
|
|
var ht = this._hTracker;
|
|
if (ht)
|
|
{
|
|
var c = this._$clip.width();
|
|
var v = this._$view.width();
|
|
ht.start(this._sx, speedX, duration, (v > c) ? -(v - c) : 0, 0);
|
|
keepGoing = !ht.done();
|
|
}
|
|
|
|
var vt = this._vTracker;
|
|
if (vt)
|
|
{
|
|
var c = this._$clip.height();
|
|
var v = this._$view.height();
|
|
vt.start(this._sy, speedY, duration, (v > c) ? -(v - c) : 0, 0);
|
|
keepGoing = keepGoing || !vt.done();
|
|
}
|
|
|
|
if (keepGoing)
|
|
this._timerID = setTimeout(this._timerCB, this._timerInterval);
|
|
else
|
|
this._stopMScroll();
|
|
},
|
|
|
|
_stopMScroll: function()
|
|
{
|
|
if (this._timerID)
|
|
{
|
|
this._$clip.trigger(this.options.stopEventName);
|
|
clearTimeout(this._timerID);
|
|
}
|
|
this._timerID = 0;
|
|
|
|
if (this._vTracker)
|
|
this._vTracker.reset();
|
|
|
|
if (this._hTracker)
|
|
this._hTracker.reset();
|
|
|
|
this._hideScrollBars();
|
|
},
|
|
|
|
_handleMomentumScroll: function()
|
|
{
|
|
var keepGoing = false;
|
|
var v = this._$view;
|
|
|
|
var x = 0, y = 0;
|
|
|
|
var vt = this._vTracker;
|
|
if (vt)
|
|
{
|
|
vt.update();
|
|
y = vt.getPosition();
|
|
keepGoing = !vt.done();
|
|
}
|
|
|
|
var ht = this._hTracker;
|
|
if (ht)
|
|
{
|
|
ht.update();
|
|
x = ht.getPosition();
|
|
keepGoing = keepGoing || !ht.done();
|
|
}
|
|
|
|
this._setScrollPosition(x, y);
|
|
this._$clip.trigger(this.options.updateEventName, { x: x, y: y });
|
|
|
|
if (keepGoing)
|
|
this._timerID = setTimeout(this._timerCB, this._timerInterval);
|
|
else
|
|
this._stopMScroll();
|
|
},
|
|
|
|
_setScrollPosition: function(x, y)
|
|
{
|
|
this._sx = x;
|
|
this._sy = y;
|
|
|
|
var kdebug = 0;
|
|
if (y == 0)
|
|
++kdebug;
|
|
|
|
var $v = this._$view;
|
|
|
|
var uct = this.options.useCSSTransform;
|
|
|
|
if (uct)
|
|
setElementTransform($v, x + "px", y + "px");
|
|
else
|
|
$v.css({left: x + "px", top: y + "px"});
|
|
|
|
var $vsb = this._$vScrollBar;
|
|
var $hsb = this._$hScrollBar;
|
|
|
|
if ($vsb || $hsb)
|
|
{
|
|
if ($vsb)
|
|
{
|
|
var $sbt = $vsb.find(".ui-scrollbar-thumb");
|
|
if (uct)
|
|
setElementTransform($sbt, "0px", -y/$v.height() * $sbt.parent().height() + "px");
|
|
else
|
|
$sbt.css("top", -y/$v.height()*100 + "%");
|
|
}
|
|
|
|
if ($hsb)
|
|
{
|
|
var $sbt = $hsb.find(".ui-scrollbar-thumb");
|
|
if (uct)
|
|
setElementTransform($sbt, -x/$v.width() * $sbt.parent().width() + "px", "0px");
|
|
else
|
|
$sbt.css("left", -x/$v.width()*100 + "%");
|
|
}
|
|
}
|
|
},
|
|
|
|
scrollTo: function(x, y, duration)
|
|
{
|
|
this._stopMScroll();
|
|
if (!duration)
|
|
return this._setScrollPosition(x, y);
|
|
|
|
x = -x;
|
|
y = -y;
|
|
|
|
var self = this;
|
|
var start = getCurrentTime();
|
|
var efunc = $.easing["easeOutQuad"];
|
|
var sx = this._sx;
|
|
var sy = this._sy;
|
|
var dx = x - sx;
|
|
var dy = y - sy;
|
|
var tfunc = function(){
|
|
var elapsed = getCurrentTime() - start;
|
|
if (elapsed >= duration)
|
|
{
|
|
self._timerID = 0;
|
|
self._setScrollPosition(x, y);
|
|
}
|
|
else
|
|
{
|
|
var ec = efunc(elapsed/duration, elapsed, 0, 1, duration);
|
|
self._setScrollPosition(sx + (dx * ec), sy + (dy * ec));
|
|
self._timerID = setTimeout(tfunc, self._timerInterval);
|
|
}
|
|
};
|
|
|
|
this._timerID = setTimeout(tfunc, this._timerInterval);
|
|
},
|
|
|
|
_getScrollPosition: function(x, y)
|
|
{
|
|
return { x: this._sx, y: this._sy };
|
|
},
|
|
|
|
_getScrollHierarchy: function()
|
|
{
|
|
var svh = [];
|
|
this._$clip.parents(".ui-scrollview-clip").each(function(){
|
|
var d = $(this).data("scrollview");
|
|
if (d) svh.unshift(d);
|
|
});
|
|
return svh;
|
|
},
|
|
|
|
_getAncestorByDirection: function(dir)
|
|
{
|
|
var svh = this._getScrollHierarchy();
|
|
var n = svh.length;
|
|
while (0 < n--)
|
|
{
|
|
var sv = svh[n];
|
|
var svdir = sv.options.direction;
|
|
|
|
if (!svdir || svdir == dir)
|
|
return sv;
|
|
}
|
|
return null;
|
|
},
|
|
|
|
_handleDragStart: function(e, ex, ey)
|
|
{
|
|
// Stop any scrolling of elements in our parent hierarcy.
|
|
$.each(this._getScrollHierarchy(),function(i,sv){ sv._stopMScroll(); });
|
|
this._stopMScroll();
|
|
|
|
var c = this._$clip;
|
|
var v = this._$view;
|
|
|
|
this._lastX = ex;
|
|
this._lastY = ey;
|
|
this._doSnapBackX = false;
|
|
this._doSnapBackY = false;
|
|
this._speedX = 0;
|
|
this._speedY = 0;
|
|
this._directionLock = "";
|
|
this._didDrag = false;
|
|
|
|
if (this._hTracker)
|
|
{
|
|
var cw = parseInt(c.css("width"), 10);
|
|
var vw = parseInt(v.css("width"), 10);
|
|
this._maxX = cw - vw;
|
|
if (this._maxX > 0) this._maxX = 0;
|
|
if (this._$hScrollBar)
|
|
this._$hScrollBar.find(".ui-scrollbar-thumb").css("width", (cw >= vw ? "100%" : Math.floor(cw/vw*100)+ "%"));
|
|
}
|
|
|
|
if (this._vTracker)
|
|
{
|
|
var ch = parseInt(c.css("height"), 10);
|
|
var vh = parseInt(v.css("height"), 10);
|
|
this._maxY = ch - vh;
|
|
if (this._maxY > 0) this._maxY = 0;
|
|
if (this._$vScrollBar)
|
|
this._$vScrollBar.find(".ui-scrollbar-thumb").css("height", (ch >= vh ? "100%" : Math.floor(ch/vh*100)+ "%"));
|
|
}
|
|
|
|
var svdir = this.options.direction;
|
|
|
|
this._pageDelta = 0;
|
|
this._pageSize = 0;
|
|
this._pagePos = 0;
|
|
|
|
if (this.options.pagingEnabled && (svdir == "x" || svdir == "y"))
|
|
{
|
|
this._pageSize = svdir == "x" ? cw : ch;
|
|
this._pagePos = svdir == "x" ? this._sx : this._sy;
|
|
this._pagePos -= this._pagePos % this._pageSize;
|
|
}
|
|
this._lastMove = 0;
|
|
this._enableTracking();
|
|
|
|
// If we're using mouse events, we need to prevent the default
|
|
// behavior to suppress accidental selection of text, etc. We
|
|
// can't do this on touch devices because it will disable the
|
|
// generation of "click" events.
|
|
//
|
|
// XXX: We should test if this has an effect on links! - kin
|
|
|
|
if (this.options.eventType == "mouse")
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
},
|
|
|
|
_propagateDragMove: function(sv, e, ex, ey, dir)
|
|
{
|
|
this._hideScrollBars();
|
|
this._disableTracking();
|
|
sv._handleDragStart(e,ex,ey);
|
|
sv._directionLock = dir;
|
|
sv._didDrag = this._didDrag;
|
|
},
|
|
|
|
_handleDragMove: function(e, ex, ey)
|
|
{
|
|
this._lastMove = getCurrentTime();
|
|
|
|
var v = this._$view;
|
|
|
|
var dx = ex - this._lastX;
|
|
var dy = ey - this._lastY;
|
|
var svdir = this.options.direction;
|
|
|
|
if (!this._directionLock)
|
|
{
|
|
var x = Math.abs(dx);
|
|
var y = Math.abs(dy);
|
|
var mt = this.options.moveThreshold;
|
|
|
|
if (x < mt && y < mt) {
|
|
return false;
|
|
}
|
|
|
|
var dir = null;
|
|
var r = 0;
|
|
if (x < y && (x/y) < 0.5) {
|
|
dir = "y";
|
|
}
|
|
else if (x > y && (y/x) < 0.5) {
|
|
dir = "x";
|
|
}
|
|
|
|
if (svdir && dir && svdir != dir)
|
|
{
|
|
// This scrollview can't handle the direction the user
|
|
// is attempting to scroll. Find an ancestor scrollview
|
|
// that can handle the request.
|
|
|
|
var sv = this._getAncestorByDirection(dir);
|
|
if (sv)
|
|
{
|
|
this._propagateDragMove(sv, e, ex, ey, dir);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
this._directionLock = svdir ? svdir : (dir ? dir : "none");
|
|
}
|
|
|
|
var newX = this._sx;
|
|
var newY = this._sy;
|
|
|
|
if (this._directionLock != "y" && this._hTracker)
|
|
{
|
|
var x = this._sx;
|
|
this._speedX = dx;
|
|
newX = x + dx;
|
|
|
|
// Simulate resistance.
|
|
|
|
this._doSnapBackX = false;
|
|
if (newX > 0 || newX < this._maxX)
|
|
{
|
|
if (this._directionLock == "x")
|
|
{
|
|
var sv = this._getAncestorByDirection("x");
|
|
if (sv)
|
|
{
|
|
this._setScrollPosition(newX > 0 ? 0 : this._maxX, newY);
|
|
this._propagateDragMove(sv, e, ex, ey, dir);
|
|
return false;
|
|
}
|
|
}
|
|
newX = x + (dx/2);
|
|
this._doSnapBackX = true;
|
|
}
|
|
}
|
|
|
|
if (this._directionLock != "x" && this._vTracker)
|
|
{
|
|
var y = this._sy;
|
|
this._speedY = dy;
|
|
newY = y + dy;
|
|
|
|
// Simulate resistance.
|
|
|
|
this._doSnapBackY = false;
|
|
if (newY > 0 || newY < this._maxY)
|
|
{
|
|
if (this._directionLock == "y")
|
|
{
|
|
var sv = this._getAncestorByDirection("y");
|
|
if (sv)
|
|
{
|
|
this._setScrollPosition(newX, newY > 0 ? 0 : this._maxY);
|
|
this._propagateDragMove(sv, e, ex, ey, dir);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
newY = y + (dy/2);
|
|
this._doSnapBackY = true;
|
|
}
|
|
|
|
}
|
|
|
|
if (this.options.pagingEnabled && (svdir == "x" || svdir == "y"))
|
|
{
|
|
if (this._doSnapBackX || this._doSnapBackY)
|
|
this._pageDelta = 0;
|
|
else
|
|
{
|
|
var opos = this._pagePos;
|
|
var cpos = svdir == "x" ? newX : newY;
|
|
var delta = svdir == "x" ? dx : dy;
|
|
|
|
this._pageDelta = (opos > cpos && delta < 0) ? this._pageSize : ((opos < cpos && delta > 0) ? -this._pageSize : 0);
|
|
}
|
|
}
|
|
|
|
this._didDrag = true;
|
|
this._lastX = ex;
|
|
this._lastY = ey;
|
|
|
|
this._setScrollPosition(newX, newY);
|
|
|
|
this._showScrollBars();
|
|
|
|
// Call preventDefault() to prevent touch devices from
|
|
// scrolling the main window.
|
|
|
|
// e.preventDefault();
|
|
|
|
return false;
|
|
},
|
|
|
|
_handleDragStop: function(e)
|
|
{
|
|
var l = this._lastMove;
|
|
var t = getCurrentTime();
|
|
var doScroll = l && (t - l) <= this.options.moveIntervalThreshold;
|
|
|
|
var sx = (this._hTracker && this._speedX && doScroll) ? this._speedX : (this._doSnapBackX ? 1 : 0);
|
|
var sy = (this._vTracker && this._speedY && doScroll) ? this._speedY : (this._doSnapBackY ? 1 : 0);
|
|
|
|
var svdir = this.options.direction;
|
|
if (this.options.pagingEnabled && (svdir == "x" || svdir == "y") && !this._doSnapBackX && !this._doSnapBackY)
|
|
{
|
|
var x = this._sx;
|
|
var y = this._sy;
|
|
if (svdir == "x")
|
|
x = -this._pagePos + this._pageDelta;
|
|
else
|
|
y = -this._pagePos + this._pageDelta;
|
|
|
|
this.scrollTo(x, y, this.options.snapbackDuration);
|
|
}
|
|
else if (sx || sy)
|
|
this._startMScroll(sx, sy);
|
|
else
|
|
this._hideScrollBars();
|
|
|
|
this._disableTracking();
|
|
|
|
// If a view scrolled, then we need to absorb
|
|
// the event so that links etc, underneath our
|
|
// cursor/finger don't fire.
|
|
|
|
return this._didDrag ? false : undefined;
|
|
},
|
|
|
|
_enableTracking: function()
|
|
{
|
|
$(document).bind(this._dragMoveEvt, this._dragMoveCB);
|
|
$(document).bind(this._dragStopEvt, this._dragStopCB);
|
|
},
|
|
|
|
_disableTracking: function()
|
|
{
|
|
$(document).unbind(this._dragMoveEvt, this._dragMoveCB);
|
|
$(document).unbind(this._dragStopEvt, this._dragStopCB);
|
|
},
|
|
|
|
_showScrollBars: function()
|
|
{
|
|
var vclass = "ui-scrollbar-visible";
|
|
if (this._$vScrollBar) this._$vScrollBar.addClass(vclass);
|
|
if (this._$hScrollBar) this._$hScrollBar.addClass(vclass);
|
|
},
|
|
|
|
_hideScrollBars: function()
|
|
{
|
|
var vclass = "ui-scrollbar-visible";
|
|
if (this._$vScrollBar) this._$vScrollBar.removeClass(vclass);
|
|
if (this._$hScrollBar) this._$hScrollBar.removeClass(vclass);
|
|
},
|
|
|
|
_addBehaviors: function()
|
|
{
|
|
var self = this;
|
|
if (this.options.eventType == "mouse")
|
|
{
|
|
this._dragStartEvt = "mousedown";
|
|
this._dragStartCB = function(e){ return self._handleDragStart(e, e.clientX, e.clientY); };
|
|
|
|
this._dragMoveEvt = "mousemove";
|
|
this._dragMoveCB = function(e){ return self._handleDragMove(e, e.clientX, e.clientY); };
|
|
|
|
this._dragStopEvt = "mouseup";
|
|
this._dragStopCB = function(e){ return self._handleDragStop(e); };
|
|
}
|
|
else // "touch"
|
|
{
|
|
this._dragStartEvt = "touchstart";
|
|
this._dragStartCB = function(e)
|
|
{
|
|
var t = e.originalEvent.targetTouches[0];
|
|
return self._handleDragStart(e, t.pageX, t.pageY);
|
|
};
|
|
|
|
this._dragMoveEvt = "touchmove";
|
|
this._dragMoveCB = function(e)
|
|
{
|
|
var t = e.originalEvent.targetTouches[0];
|
|
return self._handleDragMove(e, t.pageX, t.pageY);
|
|
};
|
|
|
|
this._dragStopEvt = "touchend";
|
|
this._dragStopCB = function(e){ return self._handleDragStop(e); };
|
|
}
|
|
|
|
this._$view.bind(this._dragStartEvt, this._dragStartCB);
|
|
|
|
if (this.options.showScrollBars)
|
|
{
|
|
var $c = this._$clip;
|
|
var prefix = "<div class=\"ui-scrollbar ui-scrollbar-";
|
|
var suffix = "\"><div class=\"ui-scrollbar-track\"><div class=\"ui-scrollbar-thumb\"></div></div></div>";
|
|
if (this._vTracker)
|
|
{
|
|
$c.append(prefix + "y" + suffix);
|
|
this._$vScrollBar = $c.children(".ui-scrollbar-y");
|
|
}
|
|
if (this._hTracker)
|
|
{
|
|
$c.append(prefix + "x" + suffix);
|
|
this._$hScrollBar = $c.children(".ui-scrollbar-x");
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
function setElementTransform($ele, x, y)
|
|
{
|
|
var v = "translate3d(" + x + "," + y + ", 0px)";
|
|
$ele.css({
|
|
"-moz-transform": v,
|
|
"-webkit-transform": v,
|
|
"transform": v
|
|
});
|
|
}
|
|
|
|
|
|
function MomentumTracker(options)
|
|
{
|
|
this.options = $.extend({}, options);
|
|
this.easing = "easeOutQuad";
|
|
this.reset();
|
|
}
|
|
|
|
var tstates = {
|
|
scrolling: 0,
|
|
overshot: 1,
|
|
snapback: 2,
|
|
done: 3
|
|
};
|
|
|
|
function getCurrentTime() { return (new Date()).getTime(); }
|
|
|
|
$.extend(MomentumTracker.prototype, {
|
|
start: function(pos, speed, duration, minPos, maxPos)
|
|
{
|
|
this.state = (speed != 0) ? ((pos < minPos || pos > maxPos) ? tstates.snapback : tstates.scrolling) : tstates.done;
|
|
this.pos = pos;
|
|
this.speed = speed;
|
|
this.duration = (this.state == tstates.snapback) ? this.options.snapbackDuration : duration;
|
|
this.minPos = minPos;
|
|
this.maxPos = maxPos;
|
|
|
|
this.fromPos = (this.state == tstates.snapback) ? this.pos : 0;
|
|
this.toPos = (this.state == tstates.snapback) ? ((this.pos < this.minPos) ? this.minPos : this.maxPos) : 0;
|
|
|
|
this.startTime = getCurrentTime();
|
|
},
|
|
|
|
reset: function()
|
|
{
|
|
this.state = tstates.done;
|
|
this.pos = 0;
|
|
this.speed = 0;
|
|
this.minPos = 0;
|
|
this.maxPos = 0;
|
|
this.duration = 0;
|
|
},
|
|
|
|
update: function()
|
|
{
|
|
var state = this.state;
|
|
if (state == tstates.done)
|
|
return this.pos;
|
|
|
|
var duration = this.duration;
|
|
var elapsed = getCurrentTime() - this.startTime;
|
|
elapsed = elapsed > duration ? duration : elapsed;
|
|
|
|
if (state == tstates.scrolling || state == tstates.overshot)
|
|
{
|
|
var dx = this.speed * (1 - $.easing[this.easing](elapsed/duration, elapsed, 0, 1, duration));
|
|
|
|
var x = this.pos + dx;
|
|
|
|
var didOverShoot = (state == tstates.scrolling) && (x < this.minPos || x > this.maxPos);
|
|
if (didOverShoot)
|
|
x = (x < this.minPos) ? this.minPos : this.maxPos;
|
|
|
|
this.pos = x;
|
|
|
|
if (state == tstates.overshot)
|
|
{
|
|
if (elapsed >= duration)
|
|
{
|
|
this.state = tstates.snapback;
|
|
this.fromPos = this.pos;
|
|
this.toPos = (x < this.minPos) ? this.minPos : this.maxPos;
|
|
this.duration = this.options.snapbackDuration;
|
|
this.startTime = getCurrentTime();
|
|
elapsed = 0;
|
|
}
|
|
}
|
|
else if (state == tstates.scrolling)
|
|
{
|
|
if (didOverShoot)
|
|
{
|
|
this.state = tstates.overshot;
|
|
this.speed = dx / 2;
|
|
this.duration = this.options.overshootDuration;
|
|
this.startTime = getCurrentTime();
|
|
}
|
|
else if (elapsed >= duration)
|
|
this.state = tstates.done;
|
|
}
|
|
}
|
|
else if (state == tstates.snapback)
|
|
{
|
|
if (elapsed >= duration)
|
|
{
|
|
this.pos = this.toPos;
|
|
this.state = tstates.done;
|
|
}
|
|
else
|
|
this.pos = this.fromPos + ((this.toPos - this.fromPos) * $.easing[this.easing](elapsed/duration, elapsed, 0, 1, duration));
|
|
}
|
|
|
|
return this.pos;
|
|
},
|
|
|
|
done: function() { return this.state == tstates.done; },
|
|
getPosition: function(){ return this.pos; }
|
|
});
|
|
|
|
jQuery.widget( "mobile.scrolllistview", jQuery.mobile.scrollview, {
|
|
options: {
|
|
direction: "y"
|
|
},
|
|
|
|
_create: function() {
|
|
$.mobile.scrollview.prototype._create.call(this);
|
|
|
|
// Cache the dividers so we don't have to search for them everytime the
|
|
// view is scrolled.
|
|
//
|
|
// XXX: Note that we need to update this cache if we ever support lists
|
|
// that can dynamically update their content.
|
|
|
|
this._$dividers = this._$view.find("[data-role=list-divider]");
|
|
this._lastDivider = null;
|
|
},
|
|
|
|
_setScrollPosition: function(x, y)
|
|
{
|
|
// Let the view scroll like it normally does.
|
|
|
|
$.mobile.scrollview.prototype._setScrollPosition.call(this, x, y);
|
|
|
|
y = -y;
|
|
|
|
// Find the dividers for the list.
|
|
|
|
var $divs = this._$dividers;
|
|
var cnt = $divs.length;
|
|
var d = null;
|
|
var dy = 0;
|
|
var nd = null;
|
|
|
|
for (var i = 0; i < cnt; i++)
|
|
{
|
|
nd = $divs.get(i);
|
|
var t = nd.offsetTop;
|
|
if (y >= t)
|
|
{
|
|
d = nd;
|
|
dy = t;
|
|
}
|
|
else if (d)
|
|
break;
|
|
}
|
|
|
|
// If we found a divider to move position it at the top of the
|
|
// clip view.
|
|
|
|
if (d)
|
|
{
|
|
var h = d.offsetHeight;
|
|
var mxy = (d != nd) ? nd.offsetTop : (this._$view.get(0).offsetHeight);
|
|
if (y + h >= mxy)
|
|
y = (mxy - h) - dy;
|
|
else
|
|
y = y - dy;
|
|
|
|
// XXX: Need to convert this over to using $().css() and supporting the non-transform case.
|
|
|
|
var ld = this._lastDivider;
|
|
if (ld && d != ld) {
|
|
setElementTransform($(ld), 0, 0);
|
|
}
|
|
setElementTransform($(d), 0, y + "px");
|
|
this._lastDivider = d;
|
|
|
|
}
|
|
}
|
|
});
|
|
|
|
})(jQuery,window,document); // End Component
|